import numpy as np
import cv2 as cv
import tkinter as tk
from tkinter import filedialog, Menu
from tkinter import simpledialog
from PIL import Image, ImageTk

class ImageViewer:
    def __init__(self, root):
        self.root = root
        self.root.title("OpenCV图像查看器")
        self.root.geometry("800x600")
        self.current_img = None  # 存储当前显示的图像

        # 创建菜单栏
        self.menu_bar = Menu(root)

        # 创建文件菜单
        self.file_menu = Menu(self.menu_bar, tearoff=0)
        self.file_menu.add_command(label="打开文件", command=self.open_file)
        self.file_menu.add_separator()
        self.file_menu.add_command(label="保存图像", command=self.save_image)
        self.file_menu.add_separator()
        self.file_menu.add_command(label="退出", command=root.quit)

        # 创建编辑菜单
        self.edit_menu = Menu(self.menu_bar, tearoff=0)
        self.edit_menu.add_command(label="旋转图像", command=self.rotate_image)
        self.edit_menu.add_command(label="平移图像", command=self.translate_image)
        self.edit_menu.add_command(label="叠加图像", command=self.overlay_image)
        self.edit_menu.add_command(label="仿射变换", command=self.affine_transform)
        self.edit_menu.add_command(label="透视变换", command=self.perspective_transform)
        self.edit_menu.add_command(label="图像金字塔", command=self.image_pyramid)
        self.edit_menu.add_command(label="矩形选择工具", command=self.rectangle_selection_tool)

        #建立形态学功能
        self.xtd_menu = Menu(self.menu_bar, tearoff=0)
        self.xtd_menu.add_command(label="腐蚀", command=self.erode_image)
        self.xtd_menu.add_command(label="膨胀", command=self.dilate_image)
        self.xtd_menu.add_command(label="开运算", command=self.opening_image)
        self.xtd_menu.add_command(label="闭运算", command=self.closing_image)
        self.xtd_menu.add_command(label="礼帽变换", command=self.tophat_image)
        self.xtd_menu.add_command(label="黑帽变换", command=self.blackhat_image)

        #建立平滑处理功能
        self.phcl_menu = Menu(self.menu_bar,tearoff=0)
        self.phcl_menu.add_command(label="均值滤波",command=self.blur_command)
        self.phcl_menu.add_command(label="高斯滤波",command=self.Gaussianblur_command)
        self.phcl_menu.add_command(label='中值滤波',command=self.medianblur_command)
        
        # 建立直方图处理功能
        self.hist_menu = Menu(self.menu_bar, tearoff=0)
        self.hist_menu.add_command(label="直方图均衡化", command=self.histogram_equalization)
        self.hist_menu.add_command(label="自适应直方图均衡化", command=self.adaptive_histogram_equalization)
        
        # 建立边缘检测功能
        self.edge_menu = Menu(self.menu_bar, tearoff=0)
        self.edge_menu.add_command(label="Sobel算子边缘检测", command=self.sobel_edge_detection)
        self.edge_menu.add_command(label="Scharr算子边缘检测", command=self.scharr_edge_detection)
        self.edge_menu.add_command(label="拉普拉斯算子边缘检测", command=self.laplacian_edge_detection)
        self.edge_menu.add_command(label="Canny边缘检测", command=self.canny_edge_detection)
        
        # 建立频域滤波功能
        self.frequency_menu = Menu(self.menu_bar, tearoff=0)
        self.frequency_menu.add_command(label="低通滤波", command=self.low_pass_filter)
        self.frequency_menu.add_command(label="高通滤波", command=self.high_pass_filter)
        self.frequency_menu.add_command(label="带通滤波", command=self.band_pass_filter)
        self.frequency_menu.add_command(label="带阻滤波", command=self.band_stop_filter)

        #建立图像分割功能
        self.segment_menu = Menu(self.menu_bar, tearoff=0)
        self.segment_menu.add_command(label="全阈值分割", command=self.full__threshold_segmentation)
        self.segment_menu.add_command(label="自适应阈值分割", command=self.adaptive_threshold_segmentation)
        self.segment_menu.add_command(label="区域填充分割", command=self.region_fill_segmentation)
        self.segment_menu.add_command(label="最小面积填充", command=self.minimum_area_fill_segmentation)
        self.segment_menu.add_command(label="大津法", command=self.otsu_segmentation)
        self.segment_menu.add_command(label="分水岭算法", command=self.watershed_segmentation)
        self.segment_menu.add_command(label="GrabCut算法", command=self.grabcut_segmentation)


        # 将菜单添加到菜单栏
        self.menu_bar.add_cascade(label="文件", menu=self.file_menu)
        self.menu_bar.add_cascade(label="编辑", menu=self.edit_menu)
        self.menu_bar.add_cascade(label="形态学",menu=self.xtd_menu)
        self.menu_bar.add_cascade(label="平滑处理",menu=self.phcl_menu)
        self.menu_bar.add_cascade(label="直方图处理", menu=self.hist_menu)
        self.menu_bar.add_cascade(label="边缘检测", menu=self.edge_menu)
        self.menu_bar.add_cascade(label="频域滤波", menu=self.frequency_menu)
        self.menu_bar.add_cascade(label="图像分割", menu=self.segment_menu)

        root.config(menu=self.menu_bar)

        # 创建图像显示标签
        # self.image_label = tk.Label(root)
        # self.image_label.pack(fill=tk.BOTH, expand=True)

        # 移除重复的图像标签创建代码，并创建分栏窗口
        # 创建分栏窗口用于显示原始图像和编辑效果（可左右拖动调整宽度）
        self.paned_window = tk.PanedWindow(root, orient=tk.HORIZONTAL, sashrelief=tk.RAISED)
        self.paned_window.pack(fill=tk.BOTH, expand=True)

        # 左侧：原始图像显示标签
        self.original_label = tk.Label(self.paned_window, text="原始图像")
        self.paned_window.add(self.original_label, width=400)  # 初始宽度

        # 右侧：编辑效果显示标签
        self.edited_label = tk.Label(self.paned_window, text="编辑效果")
        self.paned_window.add(self.edited_label, width=400)  # 初始宽度

        # 新增：创建状态栏
        self.status_bar = tk.Label(root, text="就绪", bd=1, relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

    def open_file(self):
        # 打开文件对话框
        file_path = filedialog.askopenfilename(
            filetypes=[("图像文件", "*.jpg *.jpeg *.png *.bmp *.gif")]
        )

        if file_path:
            # 使用OpenCV读取图像
            img = cv.imread(file_path)
            if img is not None:
                self.original_img = img.copy()  # 保存原始图像（不随编辑改变）
                self.current_img = img.copy()  # 保存当前编辑图像
                self.display_original(self.original_img)  # 显示原始图像
                self.display_image(self.current_img)  # 显示编辑效果（初始为原始图像）
    def rotate_image(self):
        if self.current_img is None:
            simpledialog.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 获取用户输入的旋转角度
        angle = simpledialog.askfloat(
            "旋转角度",
            "请输入旋转角度(度):",
            minvalue=-360,
            maxvalue=360
        )

        if angle is not None:  # 用户点击了确定按钮
            # 获取图像尺寸
            h, w = self.current_img.shape[:2]
            # 计算旋转中心
            center = (w / 2, h / 2)
            # 获取旋转矩阵
            rotation_matrix = cv.getRotationMatrix2D(center, angle, scale=1.0)
            # 计算旋转后的图像尺寸
            cos = np.abs(rotation_matrix[0, 0])
            sin = np.abs(rotation_matrix[0, 1])
            new_w = int((h * sin) + (w * cos))
            new_h = int((h * cos) + (w * sin))
            # 调整旋转矩阵以防止裁剪
            rotation_matrix[0, 2] += (new_w / 2) - center[0]
            rotation_matrix[1, 2] += (new_h / 2) - center[1]

            # 执行旋转
            rotated_img = cv.warpAffine(
                self.current_img,
                rotation_matrix,
                (new_w, new_h),
                borderMode=cv.BORDER_CONSTANT,
                borderValue=(255, 255, 255)  # 白色背景
            )

            # 更新当前图像并显示
            self.current_img = rotated_img
            self.display_image(rotated_img)

    def translate_image(self):
        if self.current_img is None:
            simpledialog.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 获取用户输入的水平平移距离
        dx = simpledialog.askinteger(
            "水平平移",
            "请输入水平平移距离(像素):",
            initialvalue=0
        )

        if dx is None:  # 用户取消输入
            return

        # 获取用户输入的垂直平移距离
        dy = simpledialog.askinteger(
            "垂直平移",
            "请输入垂直平移距离(像素):",
            initialvalue=0
        )

        if dy is None:  # 用户取消输入
            return

        # 获取图像尺寸
        h, w = self.current_img.shape[:2]

        # 创建平移矩阵 [1, 0, dx; 0, 1, dy]
        translation_matrix = np.float32([[1, 0, dx], [0, 1, dy]])

        # 执行平移操作
        translated_img = cv.warpAffine(
            self.current_img,
            translation_matrix,
            (w, h),
            borderMode=cv.BORDER_CONSTANT,
            borderValue=(255, 255, 255)  # 平移后空白区域填充白色
        )

        # 更新当前图像并显示
        self.current_img = translated_img
        self.display_image(translated_img)

    def overlay_image(self):
        if self.current_img is None:
            simpledialog.messagebox.showinfo("提示", "请先打开一张基础图像")
            return

        # 选择叠加图像文件
        overlay_path = filedialog.askopenfilename(
            filetypes=[("图像文件", "*.jpg *.jpeg *.png *.bmp *.gif")]
        )

        if not overlay_path:  # 用户取消选择
            return

        # 读取叠加图像
        overlay_img = cv.imread(overlay_path)
        if overlay_img is None:
            simpledialog.messagebox.showerror("错误", "无法读取选择的叠加图像")
            return

        # 获取基础图像尺寸并调整叠加图像大小以匹配
        base_h, base_w = self.current_img.shape[:2]
        overlay_img = cv.resize(overlay_img, (base_w, base_h))

        # 获取用户输入的叠加透明度 (0-1之间，0为完全透明，1为完全不透明)
        alpha = simpledialog.askfloat(
            "叠加透明度",
            "请输入叠加图像透明度 (0-1):",
            minvalue=0.0,
            maxvalue=1.0,
            initialvalue=0.5  # 默认透明度0.5
        )

        if alpha is None:  # 用户取消输入
            return

        # 计算基础图像透明度 (1 - 叠加图像透明度)
        beta = 1 - alpha
        gamma = 0  # 亮度调整参数

        # 执行图像叠加
        combined_img = cv.addWeighted(
            self.current_img,  # 基础图像
            beta,              # 基础图像权重
            overlay_img,       # 叠加图像
            alpha,             # 叠加图像权重
            gamma              # 亮度修正值
        )

        # 更新当前图像并显示结果
        self.current_img = combined_img
        self.display_image(combined_img)

        # 新增：显示原始图像的方法

    def display_original(self, img):
        # 转换BGR为RGB格式
        img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)

        # 调整图像大小以适应左侧分栏
        h, w = img_rgb.shape[:2]
        pane_width = self.paned_window.paneconfig(self.original_label, "width")[-1]
        pane_height = self.root.winfo_height() - self.status_bar.winfo_height()
        ratio = min(pane_width / w, pane_height / h) if pane_width > 0 and pane_height > 0 else 1
        new_size = (int(w * ratio), int(h * ratio))

        # 转换为Tkinter可用格式并显示
        img_pil = Image.fromarray(img_rgb).resize(new_size, Image.LANCZOS)
        img_tk = ImageTk.PhotoImage(image=img_pil)
        self.original_label.config(image=img_tk, text="")  # 清除初始提示文本
        self.original_label.image = img_tk  # 保持引用防止垃圾回收

    def display_image(self, img):
        # 转换BGR为RGB格式
        img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)

        # 调整图像大小以适应右侧分栏
        h, w = img_rgb.shape[:2]
        pane_width = self.paned_window.paneconfig(self.edited_label, "width")[-1]
        pane_height = self.root.winfo_height() - self.status_bar.winfo_height()
        ratio = min(pane_width / w, pane_height / h) if pane_width > 0 and pane_height > 0 else 1
        new_size = (int(w * ratio), int(h * ratio))

        # 转换为Tkinter可用格式并显示
        img_pil = Image.fromarray(img_rgb).resize(new_size, Image.LANCZOS)
        img_tk = ImageTk.PhotoImage(image=img_pil)
        self.edited_label.config(image=img_tk, text="")  # 清除初始提示文本
        self.edited_label.image = img_tk  # 保持引用防止垃圾回收

        # 更新状态栏信息（显示编辑后图像的属性）
        height, width = img.shape[:2]
        channels = img.shape[2] if len(img.shape) > 2 else 1
        size_kb = img.size * img.itemsize / 1024  # 计算图像大小(KB)
        status_text = f"尺寸: {width}x{height} 像素 | Shape: {img.shape} | 维度: {len(img.shape)} | 大小: {size_kb:.2f} KB"
        self.status_bar.config(text=status_text)

        # 新增：图像保存方法

    def save_image(self):
        if self.current_img is None:
            simpledialog.messagebox.showinfo("提示", "请先打开并编辑图像")
            return

        # 打开保存文件对话框
        file_path = filedialog.asksaveasfilename(
            defaultextension=".png",
            filetypes=[
                ("PNG图像", "*.png"),
                ("JPEG图像", "*.jpg;*.jpeg"),
                ("BMP图像", "*.bmp"),
                ("所有文件", "*.*")
            ]
        )
        if file_path:  # 添加实际保存功能
            # 根据文件扩展名选择适当的保存参数
            if file_path.lower().endswith(('.jpg', '.jpeg')):
                # JPEG需要指定质量参数
                cv.imwrite(file_path, self.current_img, [int(cv.IMWRITE_JPEG_QUALITY), 95])
            elif file_path.lower().endswith('.png'):
                # PNG需要指定压缩级别
                cv.imwrite(file_path, self.current_img, [int(cv.IMWRITE_PNG_COMPRESSION), 3])
            else:
                # 默认保存方式
                cv.imwrite(file_path, self.current_img)

            # 显示保存成功信息
            self.status_bar.config(text=f"图像已保存至: {file_path}")
            simpledialog.messagebox.showinfo("成功", "图像保存成功!")

    def affine_transform(self):
        """通过用户输入的对应点执行仿射变换"""
        if self.current_img is None:
            simpledialog.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建仿射变换对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("仿射变换 - 输入对应点")
        dialog.geometry("400x400")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 创建输入框标签和控件
        tk.Label(dialog, text="请输入3对对应点坐标 (x,y):", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 存储输入框的变量
        self.affine_entries = []

        # 创建输入框网格
        frame = tk.Frame(dialog)
        frame.pack(padx=20, fill=tk.X)

        # 表头
        tk.Label(frame, text="源点", width=10, font=('SimHei', 9, 'bold')).grid(row=0, column=0, padx=5, pady=5)
        tk.Label(frame, text="目标点", width=10, font=('SimHei', 9, 'bold')).grid(row=0, column=1, padx=5, pady=5)

        # 输入行
        for i in range(3):  # 3对对应点
            src_frame = tk.Frame(frame)
            src_frame.grid(row=i + 1, column=0, padx=5, pady=5)
            tk.Label(src_frame, text=f"点{i + 1}:").pack(side=tk.LEFT)
            x_entry = tk.Entry(src_frame, width=5)
            x_entry.pack(side=tk.LEFT, padx=2)
            tk.Label(src_frame, text=",").pack(side=tk.LEFT)
            y_entry = tk.Entry(src_frame, width=5)
            y_entry.pack(side=tk.LEFT, padx=2)

            dst_frame = tk.Frame(frame)
            dst_frame.grid(row=i + 1, column=1, padx=5, pady=5)
            tk.Label(dst_frame, text=f"点{i + 1}:").pack(side=tk.LEFT)
            x_entry2 = tk.Entry(dst_frame, width=5)
            x_entry2.pack(side=tk.LEFT, padx=2)
            tk.Label(dst_frame, text=",").pack(side=tk.LEFT)
            y_entry2 = tk.Entry(dst_frame, width=5)
            y_entry2.pack(side=tk.LEFT, padx=2)

            self.affine_entries.append((x_entry, y_entry, x_entry2, y_entry2))

        # 按钮框架
        btn_frame = tk.Frame(dialog)
        btn_frame.pack(pady=20)

        # 应用按钮
        def apply_affine():
            try:
                # 获取输入的点坐标
                src_pts = []
                dst_pts = []

                for entries in self.affine_entries:
                    x1, y1, x2, y2 = entries
                    src_x = float(x1.get())
                    src_y = float(y1.get())
                    dst_x = float(x2.get())
                    dst_y = float(y2.get())
                    src_pts.append([src_x, src_y])
                    dst_pts.append([dst_x, dst_y])

                # 转换为numpy数组
                src_pts = np.float32(src_pts)
                dst_pts = np.float32(dst_pts)

                # 计算仿射变换矩阵
                M = cv.getAffineTransform(src_pts, dst_pts)

                # 执行仿射变换
                rows, cols = self.current_img.shape[:2]
                transformed_img = cv.warpAffine(
                    self.current_img, M, (cols, rows),
                    borderMode=cv.BORDER_CONSTANT,
                    borderValue=(255, 255, 255)  # 空白区域填充白色
                )

                # 更新当前图像并显示
                self.current_img = transformed_img
                self.display_image(transformed_img)

                # 关闭对话框
                dialog.destroy()

            except ValueError:
                simpledialog.messagebox.showerror("错误", "请输入有效的数字坐标")
            except Exception as e:
                simpledialog.messagebox.showerror("错误", f"变换失败: {str(e)}")

        tk.Button(btn_frame, text="应用", command=apply_affine).pack(side=tk.LEFT, padx=10)
        tk.Button(btn_frame, text="取消", command=dialog.destroy).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def perspective_transform(self):
        """通过用户输入的4对对应点执行透射变换"""
        if self.current_img is None:
            simpledialog.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建透射变换对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("透射变换 - 输入对应点")
        dialog.geometry("400x500")  # 增加高度以容纳4对点输入
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 创建输入框标签和控件
        tk.Label(dialog, text="请输入4对对应点坐标 (x,y):", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 存储输入框的变量
        self.perspective_entries = []

        # 创建输入框网格
        frame = tk.Frame(dialog)
        frame.pack(padx=20, fill=tk.X)

        # 表头
        tk.Label(frame, text="源点", width=10, font=('SimHei', 9, 'bold')).grid(row=0, column=0, padx=5, pady=5)
        tk.Label(frame, text="目标点", width=10, font=('SimHei', 9, 'bold')).grid(row=0, column=1, padx=5, pady=5)

        # 输入行 - 透射变换需要4对对应点
        for i in range(4):
            src_frame = tk.Frame(frame)
            src_frame.grid(row=i + 1, column=0, padx=5, pady=5)
            tk.Label(src_frame, text=f"点{i + 1}:").pack(side=tk.LEFT)
            x_entry = tk.Entry(src_frame, width=5)
            x_entry.pack(side=tk.LEFT, padx=2)
            tk.Label(src_frame, text=",").pack(side=tk.LEFT)
            y_entry = tk.Entry(src_frame, width=5)
            y_entry.pack(side=tk.LEFT, padx=2)

            dst_frame = tk.Frame(frame)
            dst_frame.grid(row=i + 1, column=1, padx=5, pady=5)
            tk.Label(dst_frame, text=f"点{i + 1}:").pack(side=tk.LEFT)
            x_entry2 = tk.Entry(dst_frame, width=5)
            x_entry2.pack(side=tk.LEFT, padx=2)
            tk.Label(dst_frame, text=",").pack(side=tk.LEFT)
            y_entry2 = tk.Entry(dst_frame, width=5)
            y_entry2.pack(side=tk.LEFT, padx=2)

            self.perspective_entries.append((x_entry, y_entry, x_entry2, y_entry2))

        # 按钮框架
        btn_frame = tk.Frame(dialog)
        btn_frame.pack(pady=20)

        # 应用按钮
        def apply_perspective():
            try:
                # 获取输入的点坐标
                src_pts = []
                dst_pts = []

                for entries in self.perspective_entries:
                    x1, y1, x2, y2 = entries
                    src_x = float(x1.get())
                    src_y = float(y1.get())
                    dst_x = float(x2.get())
                    dst_y = float(y2.get())
                    src_pts.append([src_x, src_y])
                    dst_pts.append([dst_x, dst_y])

                # 转换为numpy数组
                src_pts = np.float32(src_pts)
                dst_pts = np.float32(dst_pts)

                # 计算透射变换矩阵 (与仿射变换的主要区别)
                M = cv.getPerspectiveTransform(src_pts, dst_pts)

                # 执行透射变换
                rows, cols = self.current_img.shape[:2]
                transformed_img = cv.warpPerspective(
                    self.current_img, M, (cols, rows),
                    borderMode=cv.BORDER_CONSTANT,
                    borderValue=(255, 255, 255)  # 空白区域填充白色
                )

                # 更新当前图像并显示
                self.current_img = transformed_img
                self.display_image(transformed_img)

                # 关闭对话框
                dialog.destroy()

            except ValueError:
                simpledialog.messagebox.showerror("错误", "请输入有效的数字坐标")
            except Exception as e:
                simpledialog.messagebox.showerror("错误", f"变换失败: {str(e)}")

        tk.Button(btn_frame, text="应用", command=apply_perspective).pack(side=tk.LEFT, padx=10)
        tk.Button(btn_frame, text="取消", command=dialog.destroy).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)


    def image_pyramid(self):
        """生成图像金字塔并在新窗口中显示结果"""
        if self.current_img is None:
            simpledialog.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建图像金字塔对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("图像金字塔参数")
        dialog.geometry("300x200")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 金字塔类型选择
        tk.Label(dialog, text="金字塔类型:").pack(pady=5)
        pyramid_type = tk.StringVar(value="gaussian")
        type_frame = tk.Frame(dialog)
        type_frame.pack()
        tk.Radiobutton(type_frame, text="高斯金字塔", variable=pyramid_type, value="gaussian").pack(side=tk.LEFT,
                                                                                                    padx=5)
        tk.Radiobutton(type_frame, text="拉普拉斯金字塔", variable=pyramid_type, value="laplacian").pack(side=tk.LEFT,
                                                                                                         padx=5)

        # 金字塔层数选择
        tk.Label(dialog, text="金字塔层数:").pack(pady=5)
        level_frame = tk.Frame(dialog)
        level_frame.pack()
        level_var = tk.IntVar(value=3)
        tk.Spinbox(level_frame, from_=1, to=6, textvariable=level_var, width=5).pack()

        # 应用按钮
        def apply_pyramid():
            try:
                # 获取参数
                pyramid_type_val = pyramid_type.get()
                levels = level_var.get()

                # 生成图像金字塔
                pyramid_images = self.generate_pyramid(self.current_img, pyramid_type_val, levels)

                # 在新窗口中显示金字塔
                self.show_pyramid_window(pyramid_images, pyramid_type_val)

                # 关闭对话框
                dialog.destroy()

            except Exception as e:
                simpledialog.messagebox.showerror("错误", f"生成金字塔失败: {str(e)}")

        btn_frame = tk.Frame(dialog)
        btn_frame.pack(pady=20)
        tk.Button(btn_frame, text="应用", command=apply_pyramid).pack(side=tk.LEFT, padx=10)
        tk.Button(btn_frame, text="取消", command=dialog.destroy).pack(side=tk.LEFT, padx=10)

        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def generate_pyramid(self, img, pyramid_type, levels):
        """生成图像金字塔"""
        pyramid = []

        if pyramid_type == "gaussian":
            # 生成高斯金字塔
            current = img.copy()
            pyramid.append(current)
            for _ in range(levels - 1):
                current = cv.pyrDown(current)
                pyramid.append(current)

        else:  # laplacian
            # 生成拉普拉斯金字塔
            gaussian = [img.copy()]
            for _ in range(levels - 1):
                gaussian.append(cv.pyrDown(gaussian[-1]))

            for i in range(levels - 1):
                size = (gaussian[i].shape[1], gaussian[i].shape[0])
                laplacian = cv.subtract(gaussian[i], cv.pyrUp(gaussian[i + 1], dstsize=size))
                pyramid.append(laplacian)
            pyramid.append(gaussian[-1])  # 添加顶层高斯图像

        return pyramid

    def show_pyramid_window(self, pyramid_images, pyramid_type):
        """在新窗口中显示金字塔图像"""
        # 创建新窗口
        pyramid_window = tk.Toplevel(self.root)
        pyramid_window.title(f"{pyramid_type}金字塔显示")
        pyramid_window.geometry("800x600")

        # 创建画布用于显示金字塔
        canvas = tk.Canvas(pyramid_window)
        canvas.pack(fill=tk.BOTH, expand=True)

        # 创建滚动条
        scroll_x = tk.Scrollbar(canvas, orient=tk.HORIZONTAL, command=canvas.xview)
        scroll_y = tk.Scrollbar(canvas, orient=tk.VERTICAL, command=canvas.yview)
        scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
        scroll_y.pack(side=tk.RIGHT, fill=tk.Y)

        # 创建框架放置金字塔图像
        frame = tk.Frame(canvas)
        canvas.create_window((0, 0), window=frame, anchor=tk.NW)

        # 显示金字塔图像
        max_width = 0
        row = 0
        col = 0
        for i, img in enumerate(pyramid_images):
            # 转换为RGB格式
            img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)

            # 调整图像大小以便显示
            h, w = img_rgb.shape[:2]
            scale = min(200 / w, 200 / h)  # 最大200x200
            new_size = (int(w * scale), int(h * scale))
            img_pil = Image.fromarray(img_rgb).resize(new_size, Image.LANCZOS)
            img_tk = ImageTk.PhotoImage(image=img_pil)

            # 创建标签显示图像
            label = tk.Label(frame, image=img_tk)
            label.image = img_tk  # 保持引用
            label.grid(row=row, column=col, padx=5, pady=5)
            tk.Label(frame, text=f"Level {i}").grid(row=row + 1, column=col, padx=5, pady=2)

            # 布局管理
            max_width += new_size[0] + 10
            col += 1
            if max_width > 700:  # 超过窗口宽度则换行
                max_width = 0
                col = 0
                row += 2

        # 更新滚动区域
        frame.update_idletasks()
        canvas.config(scrollregion=canvas.bbox("all"), xscrollcommand=scroll_x.set, yscrollcommand=scroll_y.set)

    def erode_image(self):
        """执行图像腐蚀操作"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建腐蚀参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("腐蚀参数设置")
        dialog.geometry("300x200")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 核大小输入
        tk.Label(dialog, text="请输入卷积核大小:", font=('SimHei', 10)).pack(pady=10)
        
        # 创建输入框架
        kernel_frame = tk.Frame(dialog)
        kernel_frame.pack(pady=5)
        
        tk.Label(kernel_frame, text="核大小:").pack(side=tk.LEFT, padx=5)
        kernel_var = tk.IntVar(value=3)  # 默认核大小为3
        kernel_spinbox = tk.Spinbox(kernel_frame, from_=1, to=21, textvariable=kernel_var, width=10)
        kernel_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(kernel_frame, text="(奇数)").pack(side=tk.LEFT, padx=5)

        # 迭代次数输入
        iterations_frame = tk.Frame(dialog)
        iterations_frame.pack(pady=10)
        
        tk.Label(iterations_frame, text="迭代次数:").pack(side=tk.LEFT, padx=5)
        iterations_var = tk.IntVar(value=1)  # 默认迭代次数为1
        iterations_spinbox = tk.Spinbox(iterations_frame, from_=1, to=10, textvariable=iterations_var, width=10)
        iterations_spinbox.pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_erode():
            try:
                # 获取参数
                kernel_size = kernel_var.get()
                iterations = iterations_var.get()
                
                # 确保核大小为奇数
                if kernel_size % 2 == 0:
                    kernel_size += 1
                    kernel_var.set(kernel_size)
                
                # 创建结构元素（卷积核）
                kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (kernel_size, kernel_size))
                
                # 执行腐蚀操作
                eroded_img = cv.erode(self.current_img, kernel, iterations=iterations)
                
                # 更新当前图像并显示
                self.current_img = eroded_img
                self.display_image(eroded_img)
                
                # 关闭对话框
                dialog.destroy()
                
            except Exception as e:
                tk.messagebox.showerror("错误", f"腐蚀操作失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_erode, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def dilate_image(self):
        """执行图像膨胀操作"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建膨胀参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("膨胀参数设置")
        dialog.geometry("300x200")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 核大小输入
        tk.Label(dialog, text="请输入卷积核大小:", font=('SimHei', 10)).pack(pady=10)
        
        # 创建输入框架
        kernel_frame = tk.Frame(dialog)
        kernel_frame.pack(pady=5)
        
        tk.Label(kernel_frame, text="核大小:").pack(side=tk.LEFT, padx=5)
        kernel_var = tk.IntVar(value=3)  # 默认核大小为3
        kernel_spinbox = tk.Spinbox(kernel_frame, from_=1, to=21, textvariable=kernel_var, width=10)
        kernel_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(kernel_frame, text="(奇数)").pack(side=tk.LEFT, padx=5)

        # 迭代次数输入
        iterations_frame = tk.Frame(dialog)
        iterations_frame.pack(pady=10)
        
        tk.Label(iterations_frame, text="迭代次数:").pack(side=tk.LEFT, padx=5)
        iterations_var = tk.IntVar(value=1)  # 默认迭代次数为1
        iterations_spinbox = tk.Spinbox(iterations_frame, from_=1, to=10, textvariable=iterations_var, width=10)
        iterations_spinbox.pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_dilate():
            try:
                # 获取参数
                kernel_size = kernel_var.get()
                iterations = iterations_var.get()
                
                # 确保核大小为奇数
                if kernel_size % 2 == 0:
                    kernel_size += 1
                    kernel_var.set(kernel_size)
                
                # 创建结构元素（卷积核）
                kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (kernel_size, kernel_size))
                
                # 执行膨胀操作
                dilated_img = cv.dilate(self.current_img, kernel, iterations=iterations)
                
                # 更新当前图像并显示
                self.current_img = dilated_img
                self.display_image(dilated_img)
                
                # 关闭对话框
                dialog.destroy()
                
            except Exception as e:
                tk.messagebox.showerror("错误", f"膨胀操作失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_dilate, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def opening_image(self):
        """执行图像开运算操作"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建开运算参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("开运算参数设置")
        dialog.geometry("300x200")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 核大小输入
        tk.Label(dialog, text="请输入卷积核大小:", font=('SimHei', 10)).pack(pady=10)
        
        # 创建输入框架
        kernel_frame = tk.Frame(dialog)
        kernel_frame.pack(pady=5)
        
        tk.Label(kernel_frame, text="核大小:").pack(side=tk.LEFT, padx=5)
        kernel_var = tk.IntVar(value=3)  # 默认核大小为3
        kernel_spinbox = tk.Spinbox(kernel_frame, from_=1, to=21, textvariable=kernel_var, width=10)
        kernel_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(kernel_frame, text="(奇数)").pack(side=tk.LEFT, padx=5)

        # 迭代次数输入
        iterations_frame = tk.Frame(dialog)
        iterations_frame.pack(pady=10)
        
        tk.Label(iterations_frame, text="迭代次数:").pack(side=tk.LEFT, padx=5)
        iterations_var = tk.IntVar(value=1)  # 默认迭代次数为1
        iterations_spinbox = tk.Spinbox(iterations_frame, from_=1, to=10, textvariable=iterations_var, width=10)
        iterations_spinbox.pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_opening():
            try:
                # 获取参数
                kernel_size = kernel_var.get()
                iterations = iterations_var.get()
                
                # 确保核大小为奇数
                if kernel_size % 2 == 0:
                    kernel_size += 1
                    kernel_var.set(kernel_size)
                
                # 创建结构元素（卷积核）
                kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (kernel_size, kernel_size))
                
                # 执行开运算操作（先腐蚀后膨胀）
                opening_img = cv.morphologyEx(self.current_img, cv.MORPH_OPEN, kernel, iterations=iterations)
                
                # 更新当前图像并显示
                self.current_img = opening_img
                self.display_image(opening_img)
                
                # 关闭对话框
                dialog.destroy()
                
            except Exception as e:
                tk.messagebox.showerror("错误", f"开运算操作失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_opening, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def closing_image(self):
        """执行图像闭运算操作"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建闭运算参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("闭运算参数设置")
        dialog.geometry("300x200")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 核大小输入
        tk.Label(dialog, text="请输入卷积核大小:", font=('SimHei', 10)).pack(pady=10)
        
        # 创建输入框架
        kernel_frame = tk.Frame(dialog)
        kernel_frame.pack(pady=5)
        
        tk.Label(kernel_frame, text="核大小:").pack(side=tk.LEFT, padx=5)
        kernel_var = tk.IntVar(value=3)  # 默认核大小为3
        kernel_spinbox = tk.Spinbox(kernel_frame, from_=1, to=21, textvariable=kernel_var, width=10)
        kernel_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(kernel_frame, text="(奇数)").pack(side=tk.LEFT, padx=5)

        # 迭代次数输入
        iterations_frame = tk.Frame(dialog)
        iterations_frame.pack(pady=10)
        
        tk.Label(iterations_frame, text="迭代次数:").pack(side=tk.LEFT, padx=5)
        iterations_var = tk.IntVar(value=1)  # 默认迭代次数为1
        iterations_spinbox = tk.Spinbox(iterations_frame, from_=1, to=10, textvariable=iterations_var, width=10)
        iterations_spinbox.pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_closing():
            try:
                # 获取参数
                kernel_size = kernel_var.get()
                iterations = iterations_var.get()
                
                # 确保核大小为奇数
                if kernel_size % 2 == 0:
                    kernel_size += 1
                    kernel_var.set(kernel_size)
                
                # 创建结构元素（卷积核）
                kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (kernel_size, kernel_size))
                
                # 执行闭运算操作（先膨胀后腐蚀）
                closing_img = cv.morphologyEx(self.current_img, cv.MORPH_CLOSE, kernel, iterations=iterations)
                
                # 更新当前图像并显示
                self.current_img = closing_img
                self.display_image(closing_img)
                
                # 关闭对话框
                dialog.destroy()
                
            except Exception as e:
                tk.messagebox.showerror("错误", f"闭运算操作失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_closing, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def tophat_image(self):
        """执行图像礼帽变换操作"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建礼帽变换参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("礼帽变换参数设置")
        dialog.geometry("300x180")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 核大小输入
        tk.Label(dialog, text="请输入卷积核大小:", font=('SimHei', 10)).pack(pady=10)
        
        # 创建输入框架
        kernel_frame = tk.Frame(dialog)
        kernel_frame.pack(pady=5)
        
        tk.Label(kernel_frame, text="核大小:").pack(side=tk.LEFT, padx=5)
        kernel_var = tk.IntVar(value=3)  # 默认核大小为3
        kernel_spinbox = tk.Spinbox(kernel_frame, from_=1, to=21, textvariable=kernel_var, width=10)
        kernel_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(kernel_frame, text="(奇数)").pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_tophat():
            try:
                # 获取参数
                kernel_size = kernel_var.get()
                
                # 确保核大小为奇数
                if kernel_size % 2 == 0:
                    kernel_size += 1
                    kernel_var.set(kernel_size)
                
                # 创建结构元素（卷积核）
                kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (kernel_size, kernel_size))
                
                # 执行礼帽变换操作（原图与开运算结果的差）
                tophat_img = cv.morphologyEx(self.current_img, cv.MORPH_TOPHAT, kernel)
                
                # 更新当前图像并显示
                self.current_img = tophat_img
                self.display_image(tophat_img)
                
                # 关闭对话框
                dialog.destroy()
                
            except Exception as e:
                tk.messagebox.showerror("错误", f"礼帽变换操作失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_tophat, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def blackhat_image(self):
        """执行图像黑帽变换操作"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建黑帽变换参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("黑帽变换参数设置")
        dialog.geometry("300x180")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 核大小输入
        tk.Label(dialog, text="请输入卷积核大小:", font=('SimHei', 10)).pack(pady=10)
        
        # 创建输入框架
        kernel_frame = tk.Frame(dialog)
        kernel_frame.pack(pady=5)
        
        tk.Label(kernel_frame, text="核大小:").pack(side=tk.LEFT, padx=5)
        kernel_var = tk.IntVar(value=3)  # 默认核大小为3
        kernel_spinbox = tk.Spinbox(kernel_frame, from_=1, to=21, textvariable=kernel_var, width=10)
        kernel_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(kernel_frame, text="(奇数)").pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_blackhat():
            try:
                # 获取参数
                kernel_size = kernel_var.get()
                
                # 确保核大小为奇数
                if kernel_size % 2 == 0:
                    kernel_size += 1
                    kernel_var.set(kernel_size)
                
                # 创建结构元素（卷积核）
                kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (kernel_size, kernel_size))
                
                # 执行黑帽变换操作（闭运算结果与原图的差）
                blackhat_img = cv.morphologyEx(self.current_img, cv.MORPH_BLACKHAT, kernel)
                
                # 更新当前图像并显示
                self.current_img = blackhat_img
                self.display_image(blackhat_img)
                
                # 关闭对话框
                dialog.destroy()
                
            except Exception as e:
                tk.messagebox.showerror("错误", f"黑帽变换操作失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_blackhat, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def scharr_edge_detection(self):
        """使用Scharr算子进行边缘检测"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建Scharr算子参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("Scharr算子边缘检测参数设置")
        dialog.geometry("300x200")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # Scharr参数设置
        tk.Label(dialog, text="Scharr算子参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 方向选择
        direction_frame = tk.Frame(dialog)
        direction_frame.pack(pady=10)
        tk.Label(direction_frame, text="检测方向:").pack(anchor=tk.W)
        direction_var = tk.StringVar(value="both")
        tk.Radiobutton(direction_frame, text="水平方向", variable=direction_var, value="x").pack(anchor=tk.W)
        tk.Radiobutton(direction_frame, text="垂直方向", variable=direction_var, value="y").pack(anchor=tk.W)
        tk.Radiobutton(direction_frame, text="两个方向", variable=direction_var, value="both").pack(anchor=tk.W)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_scharr_edge_detection():
            try:
                # 获取参数
                direction = direction_var.get()

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 应用Scharr算子
                if direction == "x":
                    scharr_result = cv.Scharr(gray, cv.CV_64F, 1, 0)
                elif direction == "y":
                    scharr_result = cv.Scharr(gray, cv.CV_64F, 0, 1)
                else:  # both
                    scharr_x = cv.Scharr(gray, cv.CV_64F, 1, 0)
                    scharr_y = cv.Scharr(gray, cv.CV_64F, 0, 1)
                    scharr_result = np.hypot(scharr_x, scharr_y)

                # 转换结果为uint8类型
                scharr_result = np.uint8(np.absolute(scharr_result))

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    scharr_result = cv.cvtColor(scharr_result, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = scharr_result
                self.display_image(scharr_result)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"Scharr边缘检测完成 (Direction={direction})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"Scharr边缘检测失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_scharr_edge_detection, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def laplacian_edge_detection(self):
        """使用拉普拉斯算子进行边缘检测"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建拉普拉斯算子参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("拉普拉斯算子边缘检测参数设置")
        dialog.geometry("300x200")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 拉普拉斯参数设置
        tk.Label(dialog, text="拉普拉斯算子参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # Kernel Size输入
        kernel_size_frame = tk.Frame(dialog)
        kernel_size_frame.pack(pady=5)
        tk.Label(kernel_size_frame, text="Kernel Size (1,3):").pack(side=tk.LEFT, padx=5)
        kernel_size_var = tk.IntVar(value=3)
        kernel_size_spinbox = tk.Spinbox(kernel_size_frame, values=(1, 3), 
                                        textvariable=kernel_size_var, width=10)
        kernel_size_spinbox.pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_laplacian_edge_detection():
            try:
                # 获取参数
                ksize = kernel_size_var.get()

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 应用拉普拉斯算子
                laplacian_result = cv.Laplacian(gray, cv.CV_64F, ksize=ksize)

                # 转换结果为uint8类型
                laplacian_result = np.uint8(np.absolute(laplacian_result))

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    laplacian_result = cv.cvtColor(laplacian_result, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = laplacian_result
                self.display_image(laplacian_result)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"拉普拉斯边缘检测完成 (Kernel Size={ksize})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"拉普拉斯边缘检测失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_laplacian_edge_detection, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)


    def blur_command(self):
        """执行均值滤波操作"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建均值滤波参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("均值滤波参数设置")
        dialog.geometry("300x200")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 核大小输入 (水平和垂直)
        tk.Label(dialog, text="请输入滤波核大小:", font=('SimHei', 10)).pack(pady=10)
        
        # 水平核大小输入
        kernel_x_frame = tk.Frame(dialog)
        kernel_x_frame.pack(pady=5)
        
        tk.Label(kernel_x_frame, text="水平核大小:").pack(side=tk.LEFT, padx=5)
        kernel_x_var = tk.IntVar(value=3)  # 默认核大小为3
        kernel_x_spinbox = tk.Spinbox(kernel_x_frame, from_=1, to=31, textvariable=kernel_x_var, width=10)
        kernel_x_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(kernel_x_frame, text="(奇数)").pack(side=tk.LEFT, padx=5)

        # 垂直核大小输入
        kernel_y_frame = tk.Frame(dialog)
        kernel_y_frame.pack(pady=5)
        
        tk.Label(kernel_y_frame, text="垂直核大小:").pack(side=tk.LEFT, padx=5)
        kernel_y_var = tk.IntVar(value=3)  # 默认核大小为3
        kernel_y_spinbox = tk.Spinbox(kernel_y_frame, from_=1, to=31, textvariable=kernel_y_var, width=10)
        kernel_y_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(kernel_y_frame, text="(奇数)").pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_blur():
            try:
                # 获取参数
                kernel_x = kernel_x_var.get()
                kernel_y = kernel_y_var.get()
                
                # 确保核大小为奇数
                if kernel_x % 2 == 0:
                    kernel_x += 1
                    kernel_x_var.set(kernel_x)
                    
                if kernel_y % 2 == 0:
                    kernel_y += 1
                    kernel_y_var.set(kernel_y)
                
                # 创建核大小元组
                kernel_size = (kernel_x, kernel_y)
                
                # 执行均值滤波操作
                blurred_img = cv.blur(self.current_img, kernel_size)
                
                # 更新当前图像并显示
                self.current_img = blurred_img
                self.display_image(blurred_img)
                
                # 关闭对话框
                dialog.destroy()
                
            except Exception as e:
                tk.messagebox.showerror("错误", f"均值滤波操作失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_blur, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def Gaussianblur_command(self):
        """执行高斯滤波操作"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建高斯滤波参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("高斯滤波参数设置")
        dialog.geometry("300x250")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 核大小输入 (水平和垂直)
        tk.Label(dialog, text="请输入滤波核大小:", font=('SimHei', 10)).pack(pady=10)
        
        # 水平核大小输入
        kernel_x_frame = tk.Frame(dialog)
        kernel_x_frame.pack(pady=5)
        
        tk.Label(kernel_x_frame, text="水平核大小:").pack(side=tk.LEFT, padx=5)
        kernel_x_var = tk.IntVar(value=3)  # 默认核大小为3
        kernel_x_spinbox = tk.Spinbox(kernel_x_frame, from_=1, to=31, textvariable=kernel_x_var, width=10)
        kernel_x_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(kernel_x_frame, text="(奇数)").pack(side=tk.LEFT, padx=5)

        # 垂直核大小输入
        kernel_y_frame = tk.Frame(dialog)
        kernel_y_frame.pack(pady=5)
        
        tk.Label(kernel_y_frame, text="垂直核大小:").pack(side=tk.LEFT, padx=5)
        kernel_y_var = tk.IntVar(value=3)  # 默认核大小为3
        kernel_y_spinbox = tk.Spinbox(kernel_y_frame, from_=1, to=31, textvariable=kernel_y_var, width=10)
        kernel_y_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(kernel_y_frame, text="(奇数)").pack(side=tk.LEFT, padx=5)

        # Sigma X 输入
        sigma_x_frame = tk.Frame(dialog)
        sigma_x_frame.pack(pady=5)
        
        tk.Label(sigma_x_frame, text="Sigma X:").pack(side=tk.LEFT, padx=5)
        sigma_x_var = tk.DoubleVar(value=0)  # 默认sigma为0
        sigma_x_spinbox = tk.Spinbox(sigma_x_frame, from_=0, to=10, increment=0.1, textvariable=sigma_x_var, width=10)
        sigma_x_spinbox.pack(side=tk.LEFT, padx=5)

        # Sigma Y 输入
        sigma_y_frame = tk.Frame(dialog)
        sigma_y_frame.pack(pady=5)
        
        tk.Label(sigma_y_frame, text="Sigma Y:").pack(side=tk.LEFT, padx=5)
        sigma_y_var = tk.DoubleVar(value=0)  # 默认sigma为0
        sigma_y_spinbox = tk.Spinbox(sigma_y_frame, from_=0, to=10, increment=0.1, textvariable=sigma_y_var, width=10)
        sigma_y_spinbox.pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_gaussian_blur():
            try:
                # 获取参数
                kernel_x = kernel_x_var.get()
                kernel_y = kernel_y_var.get()
                sigma_x = sigma_x_var.get()
                sigma_y = sigma_y_var.get()
                
                # 确保核大小为奇数
                if kernel_x % 2 == 0:
                    kernel_x += 1
                    kernel_x_var.set(kernel_x)
                    
                if kernel_y % 2 == 0:
                    kernel_y += 1
                    kernel_y_var.set(kernel_y)
                
                # 创建核大小元组
                kernel_size = (kernel_x, kernel_y)
                
                # 执行高斯滤波操作
                gaussian_img = cv.GaussianBlur(self.current_img, kernel_size, sigma_x, sigma_y)
                
                # 更新当前图像并显示
                self.current_img = gaussian_img
                self.display_image(gaussian_img)
                
                # 关闭对话框
                dialog.destroy()
                
            except Exception as e:
                tk.messagebox.showerror("错误", f"高斯滤波操作失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_gaussian_blur, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def medianblur_command(self):
        """执行中值滤波操作"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建中值滤波参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("中值滤波参数设置")
        dialog.geometry("300x180")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 核大小输入 (必须为奇数)
        tk.Label(dialog, text="请输入滤波核大小:", font=('SimHei', 10)).pack(pady=10)
        
        # 核大小输入框架
        kernel_frame = tk.Frame(dialog)
        kernel_frame.pack(pady=5)
        
        tk.Label(kernel_frame, text="核大小:").pack(side=tk.LEFT, padx=5)
        kernel_var = tk.IntVar(value=3)  # 默认核大小为3
        kernel_spinbox = tk.Spinbox(kernel_frame, from_=1, to=31, textvariable=kernel_var, width=10)
        kernel_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(kernel_frame, text="(奇数)").pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_median_blur():
            try:
                # 获取参数
                kernel_size = kernel_var.get()
                
                # 确保核大小为奇数
                if kernel_size % 2 == 0:
                    kernel_size += 1
                    kernel_var.set(kernel_size)
                
                # 执行中值滤波操作
                median_img = cv.medianBlur(self.current_img, kernel_size)
                
                # 更新当前图像并显示
                self.current_img = median_img
                self.display_image(median_img)
                
                # 关闭对话框
                dialog.destroy()
                
            except Exception as e:
                tk.messagebox.showerror("错误", f"中值滤波操作失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_median_blur, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def histogram_equalization(self):
        """执行直方图均衡化操作"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        try:
            # 检查图像是否为彩色图像
            if len(self.current_img.shape) == 3 and self.current_img.shape[2] == 3:
                # 彩色图像处理 - 转换到YUV色彩空间并只对Y通道进行均衡化
                # Y通道代表亮度信息
                yuv_img = cv.cvtColor(self.current_img, cv.COLOR_BGR2YUV)
                yuv_img[:,:,0] = cv.equalizeHist(yuv_img[:,:,0])
                equalized_img = cv.cvtColor(yuv_img, cv.COLOR_YUV2BGR)
            else:
                # 灰度图像处理
                equalized_img = cv.equalizeHist(self.current_img)
            
            # 更新当前图像并显示
            self.current_img = equalized_img
            self.display_image(equalized_img)
            
            # 更新状态栏信息
            self.status_bar.config(text="直方图均衡化处理完成")
            
        except Exception as e:
            tk.messagebox.showerror("错误", f"直方图均衡化操作失败: {str(e)}")

    def adaptive_histogram_equalization(self):
        """执行自适应直方图均衡化操作（CLAHE）"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建自适应直方图均衡化参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("自适应直方图均衡化参数设置")
        dialog.geometry("350x250")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # CLAHE参数设置
        tk.Label(dialog, text="CLAHE参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # Clip Limit输入
        clip_limit_frame = tk.Frame(dialog)
        clip_limit_frame.pack(pady=5)
        tk.Label(clip_limit_frame, text="Clip Limit (1-10):").pack(side=tk.LEFT, padx=5)
        clip_limit_var = tk.DoubleVar(value=2.0)
        clip_limit_spinbox = tk.Spinbox(clip_limit_frame, from_=1.0, to=10.0, increment=0.5, 
                                       textvariable=clip_limit_var, width=10)
        clip_limit_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(clip_limit_frame, text="默认值: 2.0").pack(side=tk.LEFT, padx=5)

        # Tile Grid Size输入 (水平)
        tile_grid_x_frame = tk.Frame(dialog)
        tile_grid_x_frame.pack(pady=5)
        tk.Label(tile_grid_x_frame, text="Tile Grid Size X (4-16):").pack(side=tk.LEFT, padx=5)
        tile_grid_x_var = tk.IntVar(value=8)
        tile_grid_x_spinbox = tk.Spinbox(tile_grid_x_frame, from_=4, to=16, 
                                        textvariable=tile_grid_x_var, width=10)
        tile_grid_x_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(tile_grid_x_frame, text="默认值: 8").pack(side=tk.LEFT, padx=5)

        # Tile Grid Size输入 (垂直)
        tile_grid_y_frame = tk.Frame(dialog)
        tile_grid_y_frame.pack(pady=5)
        tk.Label(tile_grid_y_frame, text="Tile Grid Size Y (4-16):").pack(side=tk.LEFT, padx=5)
        tile_grid_y_var = tk.IntVar(value=8)
        tile_grid_y_spinbox = tk.Spinbox(tile_grid_y_frame, from_=4, to=16, 
                                        textvariable=tile_grid_y_var, width=10)
        tile_grid_y_spinbox.pack(side=tk.LEFT, padx=5)
        tk.Label(tile_grid_y_frame, text="默认值: 8").pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_adaptive_histogram_equalization():
            try:
                # 获取参数
                clip_limit = clip_limit_var.get()
                tile_grid_size = (tile_grid_x_var.get(), tile_grid_y_var.get())

                # 创建CLAHE对象
                clahe = cv.createCLAHE(clipLimit=clip_limit, tileGridSize=tile_grid_size)

                # 检查图像是否为彩色图像
                if len(self.current_img.shape) == 3 and self.current_img.shape[2] == 3:
                    # 彩色图像处理 - 转换到LAB色彩空间并只对L通道进行CLAHE
                    lab_img = cv.cvtColor(self.current_img, cv.COLOR_BGR2LAB)
                    lab_img[:,:,0] = clahe.apply(lab_img[:,:,0])
                    adapted_img = cv.cvtColor(lab_img, cv.COLOR_LAB2BGR)
                else:
                    # 灰度图像处理
                    adapted_img = clahe.apply(self.current_img)

                # 更新当前图像并显示
                self.current_img = adapted_img
                self.display_image(adapted_img)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"自适应直方图均衡化处理完成 (ClipLimit={clip_limit}, TileGridSize={tile_grid_size})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"自适应直方图均衡化操作失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_adaptive_histogram_equalization, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def scharr_edge_detection(self):
        """使用Scharr算子进行边缘检测"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建Scharr算子参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("Scharr算子边缘检测参数设置")
        dialog.geometry("300x200")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # Scharr参数设置
        tk.Label(dialog, text="Scharr算子参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # Kernel Size输入
        kernel_size_frame = tk.Frame(dialog)
        kernel_size_frame.pack(pady=5)
        tk.Label(kernel_size_frame, text="Kernel Size (1,3):").pack(side=tk.LEFT, padx=5)
        kernel_size_var = tk.IntVar(value=3)
        kernel_size_spinbox = tk.Spinbox(kernel_size_frame, values=(1, 3), 
                                        textvariable=kernel_size_var, width=10)
        kernel_size_spinbox.pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_scharr_edge_detection():
            try:
                # 获取参数
                ksize = kernel_size_var.get()

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 应用Scharr算子
                scharr_result = cv.Scharr(gray, cv.CV_64F, 1, 0)

                # 转换结果为uint8类型
                scharr_result = np.uint8(np.absolute(scharr_result))

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    scharr_result = cv.cvtColor(scharr_result, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = scharr_result
                self.display_image(scharr_result)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"Scharr边缘检测完成 (Kernel Size={ksize})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"Scharr边缘检测失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_scharr_edge_detection, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def laplacian_edge_detection(self):
        """使用拉普拉斯算子进行边缘检测"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建拉普拉斯算子参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("拉普拉斯算子边缘检测参数设置")
        dialog.geometry("300x200")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 拉普拉斯参数设置
        tk.Label(dialog, text="拉普拉斯算子参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # Kernel Size输入
        kernel_size_frame = tk.Frame(dialog)
        kernel_size_frame.pack(pady=5)
        tk.Label(kernel_size_frame, text="Kernel Size (1,3):").pack(side=tk.LEFT, padx=5)
        kernel_size_var = tk.IntVar(value=3)
        kernel_size_spinbox = tk.Spinbox(kernel_size_frame, values=(1, 3), 
                                        textvariable=kernel_size_var, width=10)
        kernel_size_spinbox.pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_laplacian_edge_detection():
            try:
                # 获取参数
                ksize = kernel_size_var.get()

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 应用拉普拉斯算子
                laplacian_result = cv.Laplacian(gray, cv.CV_64F, ksize=ksize)

                # 转换结果为uint8类型
                laplacian_result = np.uint8(np.absolute(laplacian_result))

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    laplacian_result = cv.cvtColor(laplacian_result, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = laplacian_result
                self.display_image(laplacian_result)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"拉普拉斯边缘检测完成 (Kernel Size={ksize})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"拉普拉斯边缘检测失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_laplacian_edge_detection, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def region_fill_segmentation(self):
        """区域填充分割"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建区域填充分割参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("区域填充分割参数设置")
        dialog.geometry("400x400")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 区域填充分割参数设置
        tk.Label(dialog, text="区域填充分割参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 低阈值输入
        low_threshold_frame = tk.Frame(dialog)
        low_threshold_frame.pack(pady=5)
        tk.Label(low_threshold_frame, text="低阈值 (0-255):").pack(side=tk.LEFT, padx=5)
        low_threshold_var = tk.IntVar(value=50)
        low_threshold_spinbox = tk.Spinbox(low_threshold_frame, from_=0, to=255, 
                                          textvariable=low_threshold_var, width=10)
        low_threshold_spinbox.pack(side=tk.LEFT, padx=5)

        # 高阈值输入
        high_threshold_frame = tk.Frame(dialog)
        high_threshold_frame.pack(pady=5)
        tk.Label(high_threshold_frame, text="高阈值 (0-255):").pack(side=tk.LEFT, padx=5)
        high_threshold_var = tk.IntVar(value=150)
        high_threshold_spinbox = tk.Spinbox(high_threshold_frame, from_=0, to=255, 
                                           textvariable=high_threshold_var, width=10)
        high_threshold_spinbox.pack(side=tk.LEFT, padx=5)

        # 连通方式选择
        connectivity_frame = tk.Frame(dialog)
        connectivity_frame.pack(pady=10)
        tk.Label(connectivity_frame, text="连通方式:").pack(anchor=tk.W)
        connectivity_var = tk.IntVar(value=4)
        tk.Radiobutton(connectivity_frame, text="4-连通", variable=connectivity_var, value=4).pack(anchor=tk.W)
        tk.Radiobutton(connectivity_frame, text="8-连通", variable=connectivity_var, value=8).pack(anchor=tk.W)

        def apply_region_fill_segmentation():
            try:
                # 获取参数
                low_threshold = low_threshold_var.get()
                high_threshold = high_threshold_var.get()
                connectivity = connectivity_var.get()

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 应用Canny边缘检测
                edges = cv.Canny(gray, low_threshold, high_threshold)

                # 查找轮廓
                contours, _ = cv.findContours(edges, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

                # 创建填充图像
                filled_img = np.zeros_like(gray)
                
                # 填充轮廓
                for contour in contours:
                    cv.fillPoly(filled_img, [contour], 255)

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    filled_img = cv.cvtColor(filled_img, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = filled_img
                self.display_image(filled_img)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"区域填充分割完成 (Low Threshold={low_threshold}, High Threshold={high_threshold}, Connectivity={connectivity})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"区域填充分割失败: {str(e)}")

        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20, side=tk.BOTTOM, fill=tk.X)

        # 创建应用和取消按钮
        apply_button = tk.Button(button_frame, text="应用", command=apply_region_fill_segmentation, width=10)
        apply_button.pack(side=tk.LEFT, padx=10, expand=True)
        cancel_button = tk.Button(button_frame, text="取消", command=dialog.destroy, width=10)
        cancel_button.pack(side=tk.RIGHT, padx=10, expand=True)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)



    def canny_edge_detection(self):
        """使用Canny算法进行边缘检测"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建Canny边缘检测参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("Canny边缘检测参数设置")
        dialog.geometry("350x250")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # Canny参数设置
        tk.Label(dialog, text="Canny边缘检测参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # Low Threshold输入
        low_threshold_frame = tk.Frame(dialog)
        low_threshold_frame.pack(pady=5)
        tk.Label(low_threshold_frame, text="低阈值 (0-255):").pack(side=tk.LEFT, padx=5)
        low_threshold_var = tk.IntVar(value=50)
        low_threshold_spinbox = tk.Spinbox(low_threshold_frame, from_=0, to=255, 
                                          textvariable=low_threshold_var, width=10)
        low_threshold_spinbox.pack(side=tk.LEFT, padx=5)

        # High Threshold输入
        high_threshold_frame = tk.Frame(dialog)
        high_threshold_frame.pack(pady=5)
        tk.Label(high_threshold_frame, text="高阈值 (0-255):").pack(side=tk.LEFT, padx=5)
        high_threshold_var = tk.IntVar(value=150)
        high_threshold_spinbox = tk.Spinbox(high_threshold_frame, from_=0, to=255, 
                                           textvariable=high_threshold_var, width=10)
        high_threshold_spinbox.pack(side=tk.LEFT, padx=5)

        # Aperture Size输入
        aperture_size_frame = tk.Frame(dialog)
        aperture_size_frame.pack(pady=5)
        tk.Label(aperture_size_frame, text="孔径大小 (3,5,7):").pack(side=tk.LEFT, padx=5)
        aperture_size_var = tk.IntVar(value=3)
        aperture_size_spinbox = tk.Spinbox(aperture_size_frame, values=(3, 5, 7), 
                                          textvariable=aperture_size_var, width=10)
        aperture_size_spinbox.pack(side=tk.LEFT, padx=5)

        # L2 Gradient选择
        l2_gradient_frame = tk.Frame(dialog)
        l2_gradient_frame.pack(pady=10)
        l2_gradient_var = tk.BooleanVar(value=False)
        tk.Checkbutton(l2_gradient_frame, text="使用L2梯度", variable=l2_gradient_var).pack(anchor=tk.W)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_canny_edge_detection():
            try:
                # 获取参数
                low_threshold = low_threshold_var.get()
                high_threshold = high_threshold_var.get()
                aperture_size = aperture_size_var.get()
                l2_gradient = l2_gradient_var.get()

                # 确保低阈值小于高阈值
                if low_threshold >= high_threshold:
                    tk.messagebox.showwarning("警告", "低阈值应小于高阈值")
                    return

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 应用Canny边缘检测
                canny_result = cv.Canny(gray, low_threshold, high_threshold, 
                                       apertureSize=aperture_size, L2gradient=l2_gradient)

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    canny_result = cv.cvtColor(canny_result, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = canny_result
                self.display_image(canny_result)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"Canny边缘检测完成 (Low={low_threshold}, High={high_threshold}, Aperture={aperture_size})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"Canny边缘检测失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_canny_edge_detection, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def band_pass_filter(self):
        """带通滤波（频域）"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建带通滤波参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("带通滤波参数设置")
        dialog.geometry("400x400")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 带通滤波参数设置
        tk.Label(dialog, text="带通滤波参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 截止频率输入
        low_cutoff_frame = tk.Frame(dialog)
        low_cutoff_frame.pack(pady=5)
        tk.Label(low_cutoff_frame, text="低截止频率 (0-100):").pack(side=tk.LEFT, padx=5)
        low_cutoff_var = tk.IntVar(value=20)
        low_cutoff_spinbox = tk.Spinbox(low_cutoff_frame, from_=1, to=100, 
                                      textvariable=low_cutoff_var, width=10)
        low_cutoff_spinbox.pack(side=tk.LEFT, padx=5)

        high_cutoff_frame = tk.Frame(dialog)
        high_cutoff_frame.pack(pady=5)
        tk.Label(high_cutoff_frame, text="高截止频率 (0-100):").pack(side=tk.LEFT, padx=5)
        high_cutoff_var = tk.IntVar(value=50)
        high_cutoff_spinbox = tk.Spinbox(high_cutoff_frame, from_=1, to=100, 
                                       textvariable=high_cutoff_var, width=10)
        high_cutoff_spinbox.pack(side=tk.LEFT, padx=5)

        # 滤波器类型选择
        filter_type_frame = tk.Frame(dialog)
        filter_type_frame.pack(pady=10)
        tk.Label(filter_type_frame, text="滤波器类型:").pack(anchor=tk.W)
        filter_type_var = tk.StringVar(value="ideal")
        tk.Radiobutton(filter_type_frame, text="理想带通滤波器", variable=filter_type_var, value="ideal").pack(anchor=tk.W)
        tk.Radiobutton(filter_type_frame, text="巴特沃斯带通滤波器", variable=filter_type_var, value="butterworth").pack(anchor=tk.W)
        tk.Radiobutton(filter_type_frame, text="高斯带通滤波器", variable=filter_type_var, value="gaussian").pack(anchor=tk.W)

        # 巴特沃斯滤波器阶数输入（仅在选择巴特沃斯滤波器时有效）
        order_frame = tk.Frame(dialog)
        order_frame.pack(pady=5)
        tk.Label(order_frame, text="阶数 (1-10):").pack(side=tk.LEFT, padx=5)
        order_var = tk.IntVar(value=2)
        order_spinbox = tk.Spinbox(order_frame, from_=1, to=10, 
                                  textvariable=order_var, width=10)
        order_spinbox.pack(side=tk.LEFT, padx=5)

        def apply_band_pass_filter():
            try:
                # 获取参数
                low_cutoff = low_cutoff_var.get()
                high_cutoff = high_cutoff_var.get()
                filter_type = filter_type_var.get()
                order = order_var.get()

                # 确保低截止频率小于高截止频率
                if low_cutoff >= high_cutoff:
                    tk.messagebox.showwarning("警告", "低截止频率应小于高截止频率")
                    return

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 执行带通滤波
                filtered_img = self._frequency_filter(gray, (low_cutoff, high_cutoff), filter_type, order, "bandpass")

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    filtered_img = cv.cvtColor(filtered_img, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = filtered_img
                self.display_image(filtered_img)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"带通滤波完成 (Low={low_cutoff}, High={high_cutoff}, Type={filter_type})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"带通滤波失败: {str(e)}")

        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20, side=tk.BOTTOM, fill=tk.X)

        # 创建应用和取消按钮
        apply_button = tk.Button(button_frame, text="应用", command=apply_band_pass_filter, width=10)
        apply_button.pack(side=tk.LEFT, padx=10, expand=True)
        cancel_button = tk.Button(button_frame, text="取消", command=dialog.destroy, width=10)
        cancel_button.pack(side=tk.RIGHT, padx=10, expand=True)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def band_stop_filter(self):

        """带阻滤波（频域）"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建带阻滤波参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("带阻滤波参数设置")
        dialog.geometry("400x400")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 带阻滤波参数设置
        tk.Label(dialog, text="带阻滤波参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 截止频率输入
        low_cutoff_frame = tk.Frame(dialog)
        low_cutoff_frame.pack(pady=5)
        tk.Label(low_cutoff_frame, text="低截止频率 (0-100):").pack(side=tk.LEFT, padx=5)
        low_cutoff_var = tk.IntVar(value=20)
        low_cutoff_spinbox = tk.Spinbox(low_cutoff_frame, from_=1, to=100, 
                                      textvariable=low_cutoff_var, width=10)
        low_cutoff_spinbox.pack(side=tk.LEFT, padx=5)

        high_cutoff_frame = tk.Frame(dialog)
        high_cutoff_frame.pack(pady=5)
        tk.Label(high_cutoff_frame, text="高截止频率 (0-100):").pack(side=tk.LEFT, padx=5)
        high_cutoff_var = tk.IntVar(value=50)
        high_cutoff_spinbox = tk.Spinbox(high_cutoff_frame, from_=1, to=100, 
                                       textvariable=high_cutoff_var, width=10)
        high_cutoff_spinbox.pack(side=tk.LEFT, padx=5)

        # 滤波器类型选择
        filter_type_frame = tk.Frame(dialog)
        filter_type_frame.pack(pady=10)
        tk.Label(filter_type_frame, text="滤波器类型:").pack(anchor=tk.W)
        filter_type_var = tk.StringVar(value="ideal")
        tk.Radiobutton(filter_type_frame, text="理想带阻滤波器", variable=filter_type_var, value="ideal").pack(anchor=tk.W)
        tk.Radiobutton(filter_type_frame, text="巴特沃斯带阻滤波器", variable=filter_type_var, value="butterworth").pack(anchor=tk.W)

        tk.Radiobutton(filter_type_frame, text="高斯带阻滤波器", variable=filter_type_var, value="gaussian").pack(anchor=tk.W)

        # 巴特沃斯滤波器阶数输入（仅在选择巴特沃斯滤波器时有效）
        order_frame = tk.Frame(dialog)
        order_frame.pack(pady=5)
        tk.Label(order_frame, text="阶数 (1-10):").pack(side=tk.LEFT, padx=5)
        order_var = tk.IntVar(value=2)
        order_spinbox = tk.Spinbox(order_frame, from_=1, to=10, 
                                  textvariable=order_var, width=10)
        order_spinbox.pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_band_stop_filter():
            try:
                # 获取参数
                low_cutoff = low_cutoff_var.get()
                high_cutoff = high_cutoff_var.get()
                filter_type = filter_type_var.get()
                order = order_var.get()

                # 确保低截止频率小于高截止频率
                if low_cutoff >= high_cutoff:
                    tk.messagebox.showwarning("警告", "低截止频率应小于高截止频率")
                    return

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 执行带阻滤波
                filtered_img = self._frequency_filter(gray, (low_cutoff, high_cutoff), filter_type, order, "bandstop")

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    filtered_img = cv.cvtColor(filtered_img, cv.COLOR_GRAY2BGR)

                # 更新当前图像
                self.current_img = filtered_img
                self.display_image(filtered_img)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"带阻滤波完成 (Low={low_cutoff}, High={high_cutoff}, Type={filter_type})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"带阻滤波失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_band_stop_filter, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def high_pass_filter(self):
        """高通滤波（频域）"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建高通滤波参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("高通滤波参数设置")
        dialog.geometry("400x400")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 高通滤波参数设置
        tk.Label(dialog, text="高通滤波参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 截止频率输入
        cutoff_frame = tk.Frame(dialog)
        cutoff_frame.pack(pady=5)
        tk.Label(cutoff_frame, text="截止频率 (0-100):").pack(side=tk.LEFT, padx=5)
        cutoff_var = tk.IntVar(value=30)
        cutoff_spinbox = tk.Spinbox(cutoff_frame, from_=1, to=100, 
                                   textvariable=cutoff_var, width=10)
        cutoff_spinbox.pack(side=tk.LEFT, padx=5)

        # 滤波器类型选择
        filter_type_frame = tk.Frame(dialog)
        filter_type_frame.pack(pady=10)
        tk.Label(filter_type_frame, text="滤波器类型:").pack(anchor=tk.W)
        filter_type_var = tk.StringVar(value="ideal")
        tk.Radiobutton(filter_type_frame, text="理想高通滤波器", variable=filter_type_var, value="ideal").pack(anchor=tk.W)
        tk.Radiobutton(filter_type_frame, text="巴特沃斯高通滤波器", variable=filter_type_var, value="butterworth").pack(anchor=tk.W)
        tk.Radiobutton(filter_type_frame, text="高斯高通滤波器", variable=filter_type_var, value="gaussian").pack(anchor=tk.W)

        # 巴特沃斯滤波器阶数输入（仅在选择巴特沃斯滤波器时有效）
        order_frame = tk.Frame(dialog)
        order_frame.pack(pady=5)
        tk.Label(order_frame, text="阶数 (1-10):").pack(side=tk.LEFT, padx=5)
        order_var = tk.IntVar(value=2)
        order_spinbox = tk.Spinbox(order_frame, from_=1, to=10, 
                                  textvariable=order_var, width=10)
        order_spinbox.pack(side=tk.LEFT, padx=5)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_high_pass_filter():
            try:
                # 获取参数
                cutoff = cutoff_var.get()
                filter_type = filter_type_var.get()
                order = order_var.get()

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 执行高通滤波
                filtered_img = self._frequency_filter(gray, cutoff, filter_type, order, "high")

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    filtered_img = cv.cvtColor(filtered_img, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = filtered_img
                self.display_image(filtered_img)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"高通滤波完成 (Cutoff={cutoff}, Type={filter_type})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"高通滤波失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_high_pass_filter, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def low_pass_filter(self):
        """低通滤波（频域）"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建低通滤波参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("低通滤波参数设置")
        dialog.geometry("400x400")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 低通滤波参数设置
        tk.Label(dialog, text="低通滤波参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 截止频率输入
        cutoff_frame = tk.Frame(dialog)
        cutoff_frame.pack(pady=5)
        tk.Label(cutoff_frame, text="截止频率 (0-100):").pack(side=tk.LEFT, padx=5)
        cutoff_var = tk.IntVar(value=30)
        cutoff_spinbox = tk.Spinbox(cutoff_frame, from_=1, to=100, 
                                   textvariable=cutoff_var, width=10)
        cutoff_spinbox.pack(side=tk.LEFT, padx=5)

        # 滤波器类型选择
        filter_type_frame = tk.Frame(dialog)
        filter_type_frame.pack(pady=10)
        tk.Label(filter_type_frame, text="滤波器类型:").pack(anchor=tk.W)
        filter_type_var = tk.StringVar(value="ideal")
        tk.Radiobutton(filter_type_frame, text="理想低通滤波器", variable=filter_type_var, value="ideal").pack(anchor=tk.W)
        tk.Radiobutton(filter_type_frame, text="巴特沃斯低通滤波器", variable=filter_type_var, value="butterworth").pack(anchor=tk.W)
        tk.Radiobutton(filter_type_frame, text="高斯低通滤波器", variable=filter_type_var, value="gaussian").pack(anchor=tk.W)

        # 巴特沃斯滤波器阶数输入（仅在选择巴特沃斯滤波器时有效）
        order_frame = tk.Frame(dialog)
        order_frame.pack(pady=5)
        tk.Label(order_frame, text="阶数 (1-10):").pack(side=tk.LEFT, padx=5)
        order_var = tk.IntVar(value=2)
        order_spinbox = tk.Spinbox(order_frame, from_=1, to=10, 
                                  textvariable=order_var, width=10)
        order_spinbox.pack(side=tk.LEFT, padx=5)

        def apply_low_pass_filter():
            try:
                # 获取参数
                cutoff = cutoff_var.get()
                filter_type = filter_type_var.get()
                order = order_var.get()

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 执行高通滤波
                filtered_img = self._frequency_filter(gray, cutoff, filter_type, order, "high")

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    filtered_img = cv.cvtColor(filtered_img, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = filtered_img
                self.display_image(filtered_img)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"高通滤波完成 (Cutoff={cutoff}, Type={filter_type})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"高通滤波失败: {str(e)}")

        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20, side=tk.BOTTOM, fill=tk.X)

        # 创建应用和取消按钮
        apply_button = tk.Button(button_frame, text="应用", command=apply_low_pass_filter, width=10)
        apply_button.pack(side=tk.LEFT, padx=10, expand=True)
        cancel_button = tk.Button(button_frame, text="取消", command=dialog.destroy, width=10)
        cancel_button.pack(side=tk.RIGHT, padx=10, expand=True)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)


    def sobel_edge_detection(self):
        """使用Sobel算子进行边缘检测"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建Sobel算子参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("Sobel算子边缘检测参数设置")
        dialog.geometry("300x250")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # Sobel参数设置
        tk.Label(dialog, text="Sobel算子参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # Kernel Size输入
        kernel_size_frame = tk.Frame(dialog)
        kernel_size_frame.pack(pady=5)
        tk.Label(kernel_size_frame, text="Kernel Size (1,3,5,7):").pack(side=tk.LEFT, padx=5)
        kernel_size_var = tk.IntVar(value=3)
        kernel_size_spinbox = tk.Spinbox(kernel_size_frame, values=(1, 3, 5, 7), 
                                        textvariable=kernel_size_var, width=10)
        kernel_size_spinbox.pack(side=tk.LEFT, padx=5)

        # 方向选择
        direction_frame = tk.Frame(dialog)
        direction_frame.pack(pady=10)
        tk.Label(direction_frame, text="检测方向:").pack(anchor=tk.W)
        direction_var = tk.StringVar(value="both")
        tk.Radiobutton(direction_frame, text="水平方向", variable=direction_var, value="x").pack(anchor=tk.W)
        tk.Radiobutton(direction_frame, text="垂直方向", variable=direction_var, value="y").pack(anchor=tk.W)
        tk.Radiobutton(direction_frame, text="两个方向", variable=direction_var, value="both").pack(anchor=tk.W)

        # 应用和取消按钮
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20)

        def apply_sobel_edge_detection():
            try:
                # 获取参数
                ksize = kernel_size_var.get()
                direction = direction_var.get()

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 根据选择的方向应用Sobel算子
                if direction == "x":
                    sobel_result = cv.Sobel(gray, cv.CV_64F, 1, 0, ksize=ksize)
                elif direction == "y":
                    sobel_result = cv.Sobel(gray, cv.CV_64F, 0, 1, ksize=ksize)
                else:  # both
                    sobel_x = cv.Sobel(gray, cv.CV_64F, 1, 0, ksize=ksize)
                    sobel_y = cv.Sobel(gray, cv.CV_64F, 0, 1, ksize=ksize)
                    sobel_result = cv.magnitude(sobel_x, sobel_y)

                # 转换结果为uint8类型
                sobel_result = np.uint8(np.absolute(sobel_result))

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    sobel_result = cv.cvtColor(sobel_result, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = sobel_result
                self.display_image(sobel_result)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"Sobel边缘检测完成 (Kernel Size={ksize}, Direction={direction})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"Sobel边缘检测失败: {str(e)}")

        tk.Button(button_frame, text="应用", command=apply_sobel_edge_detection, width=10).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="取消", command=dialog.destroy, width=10).pack(side=tk.LEFT, padx=10)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def watershed_segmentation(self):
        """分水岭算法分割"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建分水岭算法分割参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("分水岭算法分割参数设置")
        dialog.geometry("400x400")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 分水岭算法分割参数设置
        tk.Label(dialog, text="分水岭算法分割参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 高斯模糊核大小输入
        blur_kernel_frame = tk.Frame(dialog)
        blur_kernel_frame.pack(pady=5)
        tk.Label(blur_kernel_frame, text="高斯模糊核大小 (奇数):").pack(side=tk.LEFT, padx=5)
        blur_kernel_var = tk.IntVar(value=5)
        blur_kernel_spinbox = tk.Spinbox(blur_kernel_frame, from_=3, to=31, increment=2,
                                        textvariable=blur_kernel_var, width=10)
        blur_kernel_spinbox.pack(side=tk.LEFT, padx=5)

        # 二值化阈值输入
        threshold_frame = tk.Frame(dialog)
        threshold_frame.pack(pady=5)
        tk.Label(threshold_frame, text="二值化阈值 (0-255):").pack(side=tk.LEFT, padx=5)
        threshold_var = tk.IntVar(value=127)
        threshold_spinbox = tk.Spinbox(threshold_frame, from_=0, to=255, 
                                      textvariable=threshold_var, width=10)
        threshold_spinbox.pack(side=tk.LEFT, padx=5)

        # 形态学操作核大小输入
        morph_kernel_frame = tk.Frame(dialog)
        morph_kernel_frame.pack(pady=5)
        tk.Label(morph_kernel_frame, text="形态学操作核大小 (奇数):").pack(side=tk.LEFT, padx=5)
        morph_kernel_var = tk.IntVar(value=3)
        morph_kernel_spinbox = tk.Spinbox(morph_kernel_frame, from_=3, to=21, increment=2,
                                         textvariable=morph_kernel_var, width=10)
        morph_kernel_spinbox.pack(side=tk.LEFT, padx=5)

        def apply_watershed_segmentation():
            try:
                # 获取参数
                blur_kernel = blur_kernel_var.get()
                threshold = threshold_var.get()
                morph_kernel = morph_kernel_var.get()

                # 确保核大小为奇数
                if blur_kernel % 2 == 0:
                    blur_kernel += 1
                    blur_kernel_var.set(blur_kernel)
                    
                if morph_kernel % 2 == 0:
                    morph_kernel += 1
                    morph_kernel_var.set(morph_kernel)

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 高斯模糊降噪
                blurred = cv.GaussianBlur(gray, (blur_kernel, blur_kernel), 0)

                # 二值化
                _, binary = cv.threshold(blurred, threshold, 255, cv.THRESH_BINARY)

                # 形态学操作去噪
                kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (morph_kernel, morph_kernel))
                opening = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel, iterations=2)

                # 确定背景区域
                sure_bg = cv.dilate(opening, kernel, iterations=3)

                # 确定前景区域
                dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)
                _, sure_fg = cv.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)

                # 确定未知区域
                sure_fg = np.uint8(sure_fg)
                unknown = cv.subtract(sure_bg, sure_fg)

                # 标记标记
                _, markers = cv.connectedComponents(sure_fg)
                markers = markers + 1
                markers[unknown == 255] = 0

                # 应用分水岭算法
                if len(self.current_img.shape) == 3:
                    markers = cv.watershed(self.current_img, markers)
                else:
                    # 如果是灰度图，转换为3通道
                    img_3channel = cv.cvtColor(self.current_img, cv.COLOR_GRAY2BGR)
                    markers = cv.watershed(img_3channel, markers)

                # 创建结果图像
                result_img = self.current_img.copy()
                result_img[markers == -1] = [0, 0, 255]  # 用红色标记边界

                # 更新当前图像并显示
                self.current_img = result_img
                self.display_image(result_img)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"分水岭算法分割完成 (Blur Kernel={blur_kernel}, Threshold={threshold}, Morph Kernel={morph_kernel})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"分水岭算法分割失败: {str(e)}")

        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20, side=tk.BOTTOM, fill=tk.X)

        # 创建应用和取消按钮
        apply_button = tk.Button(button_frame, text="应用", command=apply_watershed_segmentation, width=10)
        apply_button.pack(side=tk.LEFT, padx=10, expand=True)
        cancel_button = tk.Button(button_frame, text="取消", command=dialog.destroy, width=10)
        cancel_button.pack(side=tk.RIGHT, padx=10, expand=True)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def adaptive_threshold_segmentation(self):
        """自适应阈值分割"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建自适应阈值分割参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("自适应阈值分割参数设置")
        dialog.geometry("400x400")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 自适应阈值分割参数设置
        tk.Label(dialog, text="自适应阈值分割参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 最大值输入
        maxval_frame = tk.Frame(dialog)
        maxval_frame.pack(pady=5)
        tk.Label(maxval_frame, text="最大值 (0-255):").pack(side=tk.LEFT, padx=5)
        maxval_var = tk.IntVar(value=255)
        maxval_spinbox = tk.Spinbox(maxval_frame, from_=0, to=255, 
                                   textvariable=maxval_var, width=10)
        maxval_spinbox.pack(side=tk.LEFT, padx=5)

        # 自适应方法选择
        adaptive_method_frame = tk.Frame(dialog)
        adaptive_method_frame.pack(pady=10)
        tk.Label(adaptive_method_frame, text="自适应方法:").pack(anchor=tk.W)
        adaptive_method_var = tk.StringVar(value="ADAPTIVE_THRESH_MEAN_C")
        tk.Radiobutton(adaptive_method_frame, text="ADAPTIVE_THRESH_MEAN_C", variable=adaptive_method_var, value="ADAPTIVE_THRESH_MEAN_C").pack(anchor=tk.W)
        tk.Radiobutton(adaptive_method_frame, text="ADAPTIVE_THRESH_GAUSSIAN_C", variable=adaptive_method_var, value="ADAPTIVE_THRESH_GAUSSIAN_C").pack(anchor=tk.W)

        # 阈值类型选择
        threshold_type_frame = tk.Frame(dialog)
        threshold_type_frame.pack(pady=10)
        tk.Label(threshold_type_frame, text="阈值类型:").pack(anchor=tk.W)
        threshold_type_var = tk.StringVar(value="THRESH_BINARY")
        tk.Radiobutton(threshold_type_frame, text="THRESH_BINARY", variable=threshold_type_var, value="THRESH_BINARY").pack(anchor=tk.W)
        tk.Radiobutton(threshold_type_frame, text="THRESH_BINARY_INV", variable=threshold_type_var, value="THRESH_BINARY_INV").pack(anchor=tk.W)

        # blockSize输入
        blocksize_frame = tk.Frame(dialog)
        blocksize_frame.pack(pady=5)
        tk.Label(blocksize_frame, text=" blockSize (奇数):").pack(side=tk.LEFT, padx=5)
        blocksize_var = tk.IntVar(value=11)
        blocksize_spinbox = tk.Spinbox(blocksize_frame, from_=3, to=999, increment=2,
                                      textvariable=blocksize_var, width=10)
        blocksize_spinbox.pack(side=tk.LEFT, padx=5)

        # C值输入
        c_frame = tk.Frame(dialog)
        c_frame.pack(pady=5)
        tk.Label(c_frame, text="C值:").pack(side=tk.LEFT, padx=5)
        c_var = tk.IntVar(value=2)
        c_spinbox = tk.Spinbox(c_frame, from_=-100, to=100, 
                              textvariable=c_var, width=10)
        c_spinbox.pack(side=tk.LEFT, padx=5)

        def apply_adaptive_threshold_segmentation():
            try:
                # 获取参数
                maxval = maxval_var.get()
                adaptive_method = adaptive_method_var.get()
                threshold_type = threshold_type_var.get()
                blocksize = blocksize_var.get()
                c = c_var.get()

                # 确保blockSize为奇数
                if blocksize % 2 == 0:
                    blocksize += 1
                    blocksize_var.set(blocksize)

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 确保图像是8位单通道图像
                if gray.dtype != np.uint8:
                    gray = cv.normalize(gray, None, 0, 255, cv.NORM_MINMAX, dtype=cv.CV_8UC1)

                # 根据选择的自适应方法设置OpenCV自适应方法
                adaptive_method_map = {
                    "ADAPTIVE_THRESH_MEAN_C": cv.ADAPTIVE_THRESH_MEAN_C,
                    "ADAPTIVE_THRESH_GAUSSIAN_C": cv.ADAPTIVE_THRESH_GAUSSIAN_C
                }
                adaptive_method_cv = adaptive_method_map[adaptive_method]

                # 根据选择的阈值类型设置OpenCV阈值类型
                threshold_type_map = {
                    "THRESH_BINARY": cv.THRESH_BINARY,
                    "THRESH_BINARY_INV": cv.THRESH_BINARY_INV
                }
                threshold_type_cv = threshold_type_map[threshold_type]

                # 执行自适应阈值分割
                segmented_img = cv.adaptiveThreshold(gray, maxval, adaptive_method_cv, threshold_type_cv, blocksize, c)

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    segmented_img = cv.cvtColor(segmented_img, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = segmented_img
                self.display_image(segmented_img)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"自适应阈值分割完成 (Maxval={maxval}, Method={adaptive_method}, Type={threshold_type}, BlockSize={blocksize}, C={c})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"自适应阈值分割失败: {str(e)}")

        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20, side=tk.BOTTOM, fill=tk.X)

        # 创建应用和取消按钮
        apply_button = tk.Button(button_frame, text="应用", command=apply_adaptive_threshold_segmentation, width=10)
        apply_button.pack(side=tk.LEFT, padx=10, expand=True)
        cancel_button = tk.Button(button_frame, text="取消", command=dialog.destroy, width=10)
        cancel_button.pack(side=tk.RIGHT, padx=10, expand=True)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def otsu_segmentation(self):
        """大津法分割"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建大津法分割参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("大津法分割参数设置")
        dialog.geometry("400x400")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 大津法分割参数设置
        tk.Label(dialog, text="大津法分割参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 最大值输入
        maxval_frame = tk.Frame(dialog)
        maxval_frame.pack(pady=5)
        tk.Label(maxval_frame, text="最大值 (0-255):").pack(side=tk.LEFT, padx=5)
        maxval_var = tk.IntVar(value=255)
        maxval_spinbox = tk.Spinbox(maxval_frame, from_=0, to=255, 
                                   textvariable=maxval_var, width=10)
        maxval_spinbox.pack(side=tk.LEFT, padx=5)

        # 阈值类型选择
        threshold_type_frame = tk.Frame(dialog)
        threshold_type_frame.pack(pady=10)
        tk.Label(threshold_type_frame, text="阈值类型:").pack(anchor=tk.W)
        threshold_type_var = tk.StringVar(value="THRESH_BINARY")
        tk.Radiobutton(threshold_type_frame, text="THRESH_BINARY", variable=threshold_type_var, value="THRESH_BINARY").pack(anchor=tk.W)
        tk.Radiobutton(threshold_type_frame, text="THRESH_BINARY_INV", variable=threshold_type_var, value="THRESH_BINARY_INV").pack(anchor=tk.W)

        def apply_otsu_segmentation():
            try:
                # 获取参数
                maxval = maxval_var.get()
                threshold_type = threshold_type_var.get()

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 根据选择的阈值类型设置OpenCV阈值类型
                type_map = {
                    "THRESH_BINARY": cv.THRESH_BINARY,
                    "THRESH_BINARY_INV": cv.THRESH_BINARY_INV
                }
                thresh_type = type_map[threshold_type]

                # 执行大津法分割（Otsu's method）
                _, segmented_img = cv.threshold(gray, 0, maxval, thresh_type + cv.THRESH_OTSU)

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    segmented_img = cv.cvtColor(segmented_img, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = segmented_img
                self.display_image(segmented_img)

                # 获取计算出的阈值
                otsu_threshold = _
                
                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"大津法分割完成 (Threshold={otsu_threshold}, Maxval={maxval}, Type={threshold_type})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"大津法分割失败: {str(e)}")

        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20, side=tk.BOTTOM, fill=tk.X)

        # 创建应用和取消按钮
        apply_button = tk.Button(button_frame, text="应用", command=apply_otsu_segmentation, width=10)
        apply_button.pack(side=tk.LEFT, padx=10, expand=True)
        cancel_button = tk.Button(button_frame, text="取消", command=dialog.destroy, width=10)
        cancel_button.pack(side=tk.RIGHT, padx=10, expand=True)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def full__threshold_segmentation(self):
        """全阈值分割"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建全阈值分割参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("全阈值分割参数设置")
        dialog.geometry("400x400")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 全阈值分割参数设置
        tk.Label(dialog, text="全阈值分割参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 阈值输入
        threshold_frame = tk.Frame(dialog)
        threshold_frame.pack(pady=5)
        tk.Label(threshold_frame, text="阈值 (0-255):").pack(side=tk.LEFT, padx=5)
        threshold_var = tk.IntVar(value=127)
        threshold_spinbox = tk.Spinbox(threshold_frame, from_=0, to=255, 
                                      textvariable=threshold_var, width=10)
        threshold_spinbox.pack(side=tk.LEFT, padx=5)

        # 最大值输入
        maxval_frame = tk.Frame(dialog)
        maxval_frame.pack(pady=5)
        tk.Label(maxval_frame, text="最大值 (0-255):").pack(side=tk.LEFT, padx=5)
        maxval_var = tk.IntVar(value=255)
        maxval_spinbox = tk.Spinbox(maxval_frame, from_=0, to=255, 
                                   textvariable=maxval_var, width=10)
        maxval_spinbox.pack(side=tk.LEFT, padx=5)

        # 阈值类型选择
        threshold_type_frame = tk.Frame(dialog)
        threshold_type_frame.pack(pady=10)
        tk.Label(threshold_type_frame, text="阈值类型:").pack(anchor=tk.W)
        threshold_type_var = tk.StringVar(value="THRESH_BINARY")
        tk.Radiobutton(threshold_type_frame, text="THRESH_BINARY", variable=threshold_type_var, value="THRESH_BINARY").pack(anchor=tk.W)
        tk.Radiobutton(threshold_type_frame, text="THRESH_BINARY_INV", variable=threshold_type_var, value="THRESH_BINARY_INV").pack(anchor=tk.W)
        tk.Radiobutton(threshold_type_frame, text="THRESH_TRUNC", variable=threshold_type_var, value="THRESH_TRUNC").pack(anchor=tk.W)
        tk.Radiobutton(threshold_type_frame, text="THRESH_TOZERO", variable=threshold_type_var, value="THRESH_TOZERO").pack(anchor=tk.W)
        tk.Radiobutton(threshold_type_frame, text="THRESH_TOZERO_INV", variable=threshold_type_var, value="THRESH_TOZERO_INV").pack(anchor=tk.W)

        def apply_full_threshold_segmentation():
            try:
                # 获取参数
                threshold = threshold_var.get()
                maxval = maxval_var.get()
                threshold_type = threshold_type_var.get()

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 根据选择的阈值类型设置OpenCV阈值类型
                type_map = {
                    "THRESH_BINARY": cv.THRESH_BINARY,
                    "THRESH_BINARY_INV": cv.THRESH_BINARY_INV,
                    "THRESH_TRUNC": cv.THRESH_TRUNC,
                    "THRESH_TOZERO": cv.THRESH_TOZERO,
                    "THRESH_TOZERO_INV": cv.THRESH_TOZERO_INV
                }
                thresh_type = type_map[threshold_type]

                # 执行阈值分割
                _, segmented_img = cv.threshold(gray, threshold, maxval, thresh_type)

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    segmented_img = cv.cvtColor(segmented_img, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = segmented_img
                self.display_image(segmented_img)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"全阈值分割完成 (Threshold={threshold}, Maxval={maxval}, Type={threshold_type})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"全阈值分割失败: {str(e)}")

        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20, side=tk.BOTTOM, fill=tk.X)

        # 创建应用和取消按钮
        apply_button = tk.Button(button_frame, text="应用", command=apply_full_threshold_segmentation, width=10)
        apply_button.pack(side=tk.LEFT, padx=10, expand=True)
        cancel_button = tk.Button(button_frame, text="取消", command=dialog.destroy, width=10)
        cancel_button.pack(side=tk.RIGHT, padx=10, expand=True)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def minimum_area_fill_segmentation(self):
        """最小面积填充分割"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建最小面积填充分割参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("最小面积填充分割参数设置")
        dialog.geometry("400x400")
        dialog.resizable(True, True)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # 最小面积填充分割参数设置
        tk.Label(dialog, text="最小面积填充分割参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 面积阈值输入
        area_threshold_frame = tk.Frame(dialog)
        area_threshold_frame.pack(pady=5)
        tk.Label(area_threshold_frame, text="面积阈值:").pack(side=tk.LEFT, padx=5)
        area_threshold_var = tk.IntVar(value=100)
        area_threshold_spinbox = tk.Spinbox(area_threshold_frame, from_=1, to=100000, 
                                           textvariable=area_threshold_var, width=10)
        area_threshold_spinbox.pack(side=tk.LEFT, padx=5)

        # 阈值类型选择
        threshold_type_frame = tk.Frame(dialog)
        threshold_type_frame.pack(pady=10)
        tk.Label(threshold_type_frame, text="阈值类型:").pack(anchor=tk.W)
        threshold_type_var = tk.StringVar(value="THRESH_BINARY")
        tk.Radiobutton(threshold_type_frame, text="THRESH_BINARY", variable=threshold_type_var, value="THRESH_BINARY").pack(anchor=tk.W)
        tk.Radiobutton(threshold_type_frame, text="THRESH_BINARY_INV", variable=threshold_type_var, value="THRESH_BINARY_INV").pack(anchor=tk.W)

        # 阈值输入
        threshold_frame = tk.Frame(dialog)
        threshold_frame.pack(pady=5)
        tk.Label(threshold_frame, text="阈值 (0-255):").pack(side=tk.LEFT, padx=5)
        threshold_var = tk.IntVar(value=127)
        threshold_spinbox = tk.Spinbox(threshold_frame, from_=0, to=255, 
                                      textvariable=threshold_var, width=10)
        threshold_spinbox.pack(side=tk.LEFT, padx=5)

        # 最大值输入
        maxval_frame = tk.Frame(dialog)
        maxval_frame.pack(pady=5)
        tk.Label(maxval_frame, text="最大值 (0-255):").pack(side=tk.LEFT, padx=5)
        maxval_var = tk.IntVar(value=255)
        maxval_spinbox = tk.Spinbox(maxval_frame, from_=0, to=255, 
                                   textvariable=maxval_var, width=10)
        maxval_spinbox.pack(side=tk.LEFT, padx=5)

        def apply_minimum_area_fill_segmentation():
            try:
                # 获取参数
                area_threshold = area_threshold_var.get()
                threshold_type = threshold_type_var.get()
                threshold = threshold_var.get()
                maxval = maxval_var.get()

                # 将图像转换为灰度图
                if len(self.current_img.shape) == 3:
                    gray = cv.cvtColor(self.current_img, cv.COLOR_BGR2GRAY)
                else:
                    gray = self.current_img

                # 根据选择的阈值类型设置OpenCV阈值类型
                type_map = {
                    "THRESH_BINARY": cv.THRESH_BINARY,
                    "THRESH_BINARY_INV": cv.THRESH_BINARY_INV
                }
                thresh_type = type_map[threshold_type]

                # 执行阈值分割
                _, binary = cv.threshold(gray, threshold, maxval, thresh_type)

                # 查找轮廓
                contours, _ = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

                # 创建结果图像
                result_img = np.zeros_like(gray)

                # 只填充面积大于阈值的轮廓
                for contour in contours:
                    area = cv.contourArea(contour)
                    if area >= area_threshold:
                        cv.fillPoly(result_img, [contour], 255)

                # 如果原图是彩色图像，则将结果转换为彩色图像
                if len(self.current_img.shape) == 3:
                    result_img = cv.cvtColor(result_img, cv.COLOR_GRAY2BGR)

                # 更新当前图像并显示
                self.current_img = result_img
                self.display_image(result_img)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"最小面积填充分割完成 (Area Threshold={area_threshold}, Threshold Type={threshold_type})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"最小面积填充分割失败: {str(e)}")

        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20, side=tk.BOTTOM, fill=tk.X)

        # 创建应用和取消按钮
        apply_button = tk.Button(button_frame, text="应用", command=apply_minimum_area_fill_segmentation, width=10)
        apply_button.pack(side=tk.LEFT, padx=10, expand=True)
        cancel_button = tk.Button(button_frame, text="取消", command=dialog.destroy, width=10)
        cancel_button.pack(side=tk.RIGHT, padx=10, expand=True)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def grabcut_segmentation(self):
        """GrabCut算法分割"""
        if self.current_img is None:
            tk.messagebox.showinfo("提示", "请先打开一张图像")
            return

        # 创建GrabCut算法分割参数对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("GrabCut算法分割参数设置")
        dialog.geometry("350x400")
        dialog.resizable(False, False)

        # 居中显示对话框
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (dialog.winfo_screenwidth() // 2) - (width // 2)
        y = (dialog.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry('{}x{}+{}+{}'.format(width, height, x, y))

        # GrabCut算法分割参数设置
        tk.Label(dialog, text="GrabCut算法分割参数设置:", font=('SimHei', 10, 'bold')).pack(pady=10)

        # 矩形区域坐标输入
        rect_frame = tk.Frame(dialog)
        rect_frame.pack(pady=5)
        tk.Label(rect_frame, text="矩形区域 (x, y, w, h):").pack(anchor=tk.W)
        
        rect_x_frame = tk.Frame(rect_frame)
        rect_x_frame.pack(pady=2)
        tk.Label(rect_x_frame, text="X:").pack(side=tk.LEFT, padx=5)
        rect_x_var = tk.IntVar(value=50)
        rect_x_spinbox = tk.Spinbox(rect_x_frame, from_=0, to=10000, 
                                   textvariable=rect_x_var, width=8)
        rect_x_spinbox.pack(side=tk.LEFT, padx=5)

        rect_y_frame = tk.Frame(rect_frame)
        rect_y_frame.pack(pady=2)
        tk.Label(rect_y_frame, text="Y:").pack(side=tk.LEFT, padx=5)
        rect_y_var = tk.IntVar(value=50)
        rect_y_spinbox = tk.Spinbox(rect_y_frame, from_=0, to=10000, 
                                   textvariable=rect_y_var, width=8)
        rect_y_spinbox.pack(side=tk.LEFT, padx=5)

        rect_w_frame = tk.Frame(rect_frame)
        rect_w_frame.pack(pady=2)
        tk.Label(rect_w_frame, text="W:").pack(side=tk.LEFT, padx=5)
        rect_w_var = tk.IntVar(value=200)
        rect_w_spinbox = tk.Spinbox(rect_w_frame, from_=1, to=10000, 
                                   textvariable=rect_w_var, width=8)
        rect_w_spinbox.pack(side=tk.LEFT, padx=5)

        rect_h_frame = tk.Frame(rect_frame)
        rect_h_frame.pack(pady=2)
        tk.Label(rect_h_frame, text="H:").pack(side=tk.LEFT, padx=5)
        rect_h_var = tk.IntVar(value=200)
        rect_h_spinbox = tk.Spinbox(rect_h_frame, from_=1, to=10000, 
                                   textvariable=rect_h_var, width=8)
        rect_h_spinbox.pack(side=tk.LEFT, padx=5)

        # 迭代次数输入
        iterations_frame = tk.Frame(dialog)
        iterations_frame.pack(pady=5)
        tk.Label(iterations_frame, text="迭代次数:").pack(side=tk.LEFT, padx=5)
        iterations_var = tk.IntVar(value=5)
        iterations_spinbox = tk.Spinbox(iterations_frame, from_=1, to=20, 
                                       textvariable=iterations_var, width=10)
        iterations_spinbox.pack(side=tk.LEFT, padx=5)

        # 模式选择
        mode_frame = tk.Frame(dialog)
        mode_frame.pack(pady=10)
        tk.Label(mode_frame, text="模式:").pack(anchor=tk.W)
        mode_var = tk.StringVar(value="GC_INIT_WITH_RECT")
        tk.Radiobutton(mode_frame, text="GC_INIT_WITH_RECT (矩形初始化)", 
                      variable=mode_var, value="GC_INIT_WITH_RECT").pack(anchor=tk.W)
        tk.Radiobutton(mode_frame, text="GC_INIT_WITH_MASK (掩码初始化)", 
                      variable=mode_var, value="GC_INIT_WITH_MASK").pack(anchor=tk.W)

        def apply_grabcut_segmentation():
            try:
                # 获取参数
                rect_x = rect_x_var.get()
                rect_y = rect_y_var.get()
                rect_w = rect_w_var.get()
                rect_h = rect_h_var.get()
                iterations = iterations_var.get()
                mode = mode_var.get()

                # 检查矩形区域是否有效
                img_h, img_w = self.current_img.shape[:2]
                if rect_x < 0 or rect_y < 0 or rect_x + rect_w > img_w or rect_y + rect_h > img_h:
                    tk.messagebox.showwarning("警告", "矩形区域超出图像边界")
                    return

                # 定义矩形区域
                rect = (rect_x, rect_y, rect_w, rect_h)

                # 创建输入图像的副本
                img_copy = self.current_img.copy()
                
                # 创建掩码
                mask = np.zeros(img_copy.shape[:2], np.uint8)
                
                # 创建背景和前景模型
                bgdModel = np.zeros((1, 65), np.float64)
                fgdModel = np.zeros((1, 65), np.float64)

                # 根据模式选择初始化方式
                if mode == "GC_INIT_WITH_RECT":
                    # 使用矩形初始化
                    cv.grabCut(img_copy, mask, rect, bgdModel, fgdModel, iterations, cv.GC_INIT_WITH_RECT)
                else:
                    # 使用掩码初始化，这里简单地将矩形区域设为可能的前景
                    mask[rect_y:rect_y+rect_h, rect_x:rect_x+rect_w] = cv.GC_PR_FGD
                    cv.grabCut(img_copy, mask, rect, bgdModel, fgdModel, iterations, cv.GC_INIT_WITH_MASK)

                # 创建结果掩码（确定的前景和可能的前景都视为前景）
                mask_result = np.where((mask == cv.GC_FGD) | (mask == cv.GC_PR_FGD), 255, 0).astype('uint8')
                
                # 应用掩码到原图像
                result_img = cv.bitwise_and(img_copy, img_copy, mask=mask_result)
                
                # 创建带透明背景的结果图像
                b, g, r = cv.split(result_img)
                rgba = [b, g, r, mask_result]
                result_with_alpha = cv.merge(rgba, 4)

                # 更新当前图像并显示
                self.current_img = result_img
                self.display_image(result_img)

                # 关闭对话框
                dialog.destroy()

                # 更新状态栏信息
                self.status_bar.config(text=f"GrabCut算法分割完成 (Rect=({rect_x},{rect_y},{rect_w},{rect_h}), Iterations={iterations})")

            except Exception as e:
                tk.messagebox.showerror("错误", f"GrabCut算法分割失败: {str(e)}")

        # 创建按钮框架
        button_frame = tk.Frame(dialog)
        button_frame.pack(pady=20, side=tk.BOTTOM, fill=tk.X)

        # 创建应用和取消按钮
        apply_button = tk.Button(button_frame, text="应用", command=apply_grabcut_segmentation, width=10)
        apply_button.pack(side=tk.LEFT, padx=10, expand=True)
        cancel_button = tk.Button(button_frame, text="取消", command=dialog.destroy, width=10)
        cancel_button.pack(side=tk.RIGHT, padx=10, expand=True)

        # 显示对话框
        dialog.transient(self.root)
        dialog.grab_set()
        self.root.wait_window(dialog)

    def _frequency_filter(self, img, cutoff, filter_type, order, filter_kind):
        """
        频域滤波核心处理函数
        
        参数:
        img: 输入图像
        cutoff: 截止频率或频率范围
        filter_type: 滤波器类型 ("ideal", "butterworth", "gaussian")
        order: 滤波器阶数（仅巴特沃斯滤波器使用）
        filter_kind: 滤波器种类 ("low", "high", "bandpass", "bandstop")
        """
        # 获取图像尺寸
        rows, cols = img.shape
        crow, ccol = rows // 2, cols // 2

        # 创建频率域坐标网格
        u = np.arange(rows).reshape(-1, 1) - crow
        v = np.arange(cols).reshape(1, -1) - ccol
        D = np.sqrt(u**2 + v**2)

        # 根据滤波器种类创建滤波器掩码
        if filter_kind == "low":
            # 低通滤波器
            if filter_type == "ideal":
                mask = np.where(D <= cutoff, 1, 0)
            elif filter_type == "butterworth":
                mask = 1 / (1 + (D / cutoff)**(2 * order))
            else:  # gaussian
                mask = np.exp(-(D**2) / (2 * (cutoff**2)))
                
        elif filter_kind == "high":
            # 高通滤波器
            if filter_type == "ideal":
                mask = np.where(D > cutoff, 1, 0)
            elif filter_type == "butterworth":
                # 避免除零错误
                mask = 1 / (1 + (cutoff / (D + 1e-10))**(2 * order))
            else:  # gaussian
                mask = 1 - np.exp(-(D**2) / (2 * (cutoff**2)))
                
        elif filter_kind == "bandpass":
            # 带通滤波器
            low_cutoff, high_cutoff = cutoff
            if filter_type == "ideal":
                mask = np.where((D >= low_cutoff) & (D <= high_cutoff), 1, 0)
            elif filter_type == "butterworth":
                # 两个低通滤波器相减实现带通
                mask1 = 1 / (1 + (D / high_cutoff)**(2 * order))
                mask2 = 1 / (1 + (D / low_cutoff)**(2 * order))
                mask = mask1 - mask2
            else:  # gaussian
                mask1 = np.exp(-(D**2) / (2 * (high_cutoff**2)))
                mask2 = np.exp(-(D**2) / (2 * (low_cutoff**2)))
                mask = mask1 - mask2
                
        else:  # bandstop
            # 带阻滤波器
            low_cutoff, high_cutoff = cutoff
            if filter_type == "ideal":
                mask = np.where((D < low_cutoff) | (D > high_cutoff), 1, 0)
            elif filter_type == "butterworth":
                # 两个低通滤波器相减实现带阻
                mask1 = 1 / (1 + (D / high_cutoff)**(2 * order))
                mask2 = 1 / (1 + (D / low_cutoff)**(2 * order))
                mask = 1 - (mask1 - mask2)
            else:  # gaussian
                mask1 = np.exp(-(D**2) / (2 * (high_cutoff**2)))
                mask2 = np.exp(-(D**2) / (2 * (low_cutoff**2)))
                mask = 1 - (mask1 - mask2)

        # 傅里叶变换
        f = np.fft.fft2(img)
        fshift = np.fft.fftshift(f)

        # 应用滤波器
        filtered_fshift = fshift * mask

        # 反傅里叶变换
        f_ishift = np.fft.ifftshift(filtered_fshift)
        img_back = np.fft.ifft2(f_ishift)
        img_back = np.abs(img_back)

        # 转换为uint8类型
        img_back = np.uint8(np.clip(img_back, 0, 255))
        
        return img_back

    def rectangle_selection_tool(self):
        from rectangle_selector import RectangleSelector
        root2 = tk.Tk()
        app2 = RectangleSelector(root)
        root2.mainloop()

if __name__ == "__main__":
    root = tk.Tk()
    app = ImageViewer(root)
    root.mainloop()
